diff options
-rw-r--r-- | include/linux/pci_ids.h | 1 | ||||
-rw-r--r-- | sound/pci/ctxfi/ct20k2reg.h | 1 | ||||
-rw-r--r-- | sound/pci/ctxfi/ctatc.c | 124 | ||||
-rw-r--r-- | sound/pci/ctxfi/ctatc.h | 8 | ||||
-rw-r--r-- | sound/pci/ctxfi/ctdaio.c | 23 | ||||
-rw-r--r-- | sound/pci/ctxfi/ctdaio.h | 1 | ||||
-rw-r--r-- | sound/pci/ctxfi/cthardware.h | 8 | ||||
-rw-r--r-- | sound/pci/ctxfi/cthw20k1.c | 18 | ||||
-rw-r--r-- | sound/pci/ctxfi/cthw20k2.c | 323 | ||||
-rw-r--r-- | sound/pci/ctxfi/ctmixer.c | 141 | ||||
-rw-r--r-- | sound/pci/ctxfi/xfi.c | 4 |
11 files changed, 488 insertions, 164 deletions
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index a311008af5e1..f23f8bf02b04 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -1308,6 +1308,7 @@ | |||
1308 | #define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041 | 1308 | #define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041 |
1309 | #define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042 | 1309 | #define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042 |
1310 | #define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043 | 1310 | #define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043 |
1311 | #define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062 | ||
1311 | #define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000 | 1312 | #define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000 |
1312 | 1313 | ||
1313 | #define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */ | 1314 | #define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */ |
diff --git a/sound/pci/ctxfi/ct20k2reg.h b/sound/pci/ctxfi/ct20k2reg.h index e0394e3996e8..ca501ba03d64 100644 --- a/sound/pci/ctxfi/ct20k2reg.h +++ b/sound/pci/ctxfi/ct20k2reg.h | |||
@@ -55,6 +55,7 @@ | |||
55 | /* GPIO Registers */ | 55 | /* GPIO Registers */ |
56 | #define GPIO_DATA 0x1B7020 | 56 | #define GPIO_DATA 0x1B7020 |
57 | #define GPIO_CTRL 0x1B7024 | 57 | #define GPIO_CTRL 0x1B7024 |
58 | #define GPIO_EXT_DATA 0x1B70A0 | ||
58 | 59 | ||
59 | /* Virtual memory registers */ | 60 | /* Virtual memory registers */ |
60 | #define VMEM_PTPAL 0x1C6300 /* 0x1C6300 + (16 * Chn) */ | 61 | #define VMEM_PTPAL 0x1C6300 /* 0x1C6300 + (16 * Chn) */ |
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 13f33c0719d3..952fd94c2666 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <sound/asoundef.h> | 30 | #include <sound/asoundef.h> |
31 | 31 | ||
32 | #define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ | 32 | #define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ |
33 | #define DAIONUM 7 | ||
34 | #define MAX_MULTI_CHN 8 | 33 | #define MAX_MULTI_CHN 8 |
35 | 34 | ||
36 | #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \ | 35 | #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \ |
@@ -53,6 +52,8 @@ static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { | |||
53 | static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { | 52 | static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { |
54 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, | 53 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, |
55 | "SB0760", CTSB0760), | 54 | "SB0760", CTSB0760), |
55 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270, | ||
56 | "SB1270", CTSB1270), | ||
56 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801, | 57 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801, |
57 | "SB0880", CTSB0880), | 58 | "SB0880", CTSB0880), |
58 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802, | 59 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802, |
@@ -75,6 +76,7 @@ static const char *ct_subsys_name[NUM_CTCARDS] = { | |||
75 | [CTSB0760] = "SB076x", | 76 | [CTSB0760] = "SB076x", |
76 | [CTHENDRIX] = "Hendrix", | 77 | [CTHENDRIX] = "Hendrix", |
77 | [CTSB0880] = "SB0880", | 78 | [CTSB0880] = "SB0880", |
79 | [CTSB1270] = "SB1270", | ||
78 | [CT20K2_UNKNOWN] = "Unknown", | 80 | [CT20K2_UNKNOWN] = "Unknown", |
79 | }; | 81 | }; |
80 | 82 | ||
@@ -459,12 +461,12 @@ static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm, | |||
459 | apcm->substream->runtime->rate); | 461 | apcm->substream->runtime->rate); |
460 | *n_srcc = 0; | 462 | *n_srcc = 0; |
461 | 463 | ||
462 | if (1 == atc->msr) { | 464 | if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */ |
463 | *n_srcc = apcm->substream->runtime->channels; | 465 | *n_srcc = apcm->substream->runtime->channels; |
464 | conf[0].pitch = pitch; | 466 | conf[0].pitch = pitch; |
465 | conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1; | 467 | conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1; |
466 | conf[0].vo = 1; | 468 | conf[0].vo = 1; |
467 | } else if (2 == atc->msr) { | 469 | } else if (2 <= atc->msr) { |
468 | if (0x8000000 < pitch) { | 470 | if (0x8000000 < pitch) { |
469 | /* Need two-stage SRCs, SRCIMPs and | 471 | /* Need two-stage SRCs, SRCIMPs and |
470 | * AMIXERs for converting format */ | 472 | * AMIXERs for converting format */ |
@@ -977,6 +979,55 @@ static int atc_have_digit_io_switch(struct ct_atc *atc) | |||
977 | return hw->have_digit_io_switch(hw); | 979 | return hw->have_digit_io_switch(hw); |
978 | } | 980 | } |
979 | 981 | ||
982 | static int atc_have_dedicated_mic(struct ct_atc *atc) | ||
983 | { | ||
984 | struct hw *hw = atc->hw; | ||
985 | |||
986 | return hw->have_dedicated_mic(hw); | ||
987 | } | ||
988 | |||
989 | static int atc_have_output_switch(struct ct_atc *atc) | ||
990 | { | ||
991 | struct hw *hw = atc->hw; | ||
992 | |||
993 | return hw->have_output_switch(hw); | ||
994 | } | ||
995 | |||
996 | static int atc_output_switch_get(struct ct_atc *atc) | ||
997 | { | ||
998 | struct hw *hw = atc->hw; | ||
999 | |||
1000 | return hw->output_switch_get(hw); | ||
1001 | } | ||
1002 | |||
1003 | static int atc_output_switch_put(struct ct_atc *atc, int position) | ||
1004 | { | ||
1005 | struct hw *hw = atc->hw; | ||
1006 | |||
1007 | return hw->output_switch_put(hw, position); | ||
1008 | } | ||
1009 | |||
1010 | static int atc_have_mic_source_switch(struct ct_atc *atc) | ||
1011 | { | ||
1012 | struct hw *hw = atc->hw; | ||
1013 | |||
1014 | return hw->have_mic_source_switch(hw); | ||
1015 | } | ||
1016 | |||
1017 | static int atc_mic_source_switch_get(struct ct_atc *atc) | ||
1018 | { | ||
1019 | struct hw *hw = atc->hw; | ||
1020 | |||
1021 | return hw->mic_source_switch_get(hw); | ||
1022 | } | ||
1023 | |||
1024 | static int atc_mic_source_switch_put(struct ct_atc *atc, int position) | ||
1025 | { | ||
1026 | struct hw *hw = atc->hw; | ||
1027 | |||
1028 | return hw->mic_source_switch_put(hw, position); | ||
1029 | } | ||
1030 | |||
980 | static int atc_select_digit_io(struct ct_atc *atc) | 1031 | static int atc_select_digit_io(struct ct_atc *atc) |
981 | { | 1032 | { |
982 | struct hw *hw = atc->hw; | 1033 | struct hw *hw = atc->hw; |
@@ -1045,6 +1096,11 @@ static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state) | |||
1045 | return atc_daio_unmute(atc, state, LINEIM); | 1096 | return atc_daio_unmute(atc, state, LINEIM); |
1046 | } | 1097 | } |
1047 | 1098 | ||
1099 | static int atc_mic_unmute(struct ct_atc *atc, unsigned char state) | ||
1100 | { | ||
1101 | return atc_daio_unmute(atc, state, MIC); | ||
1102 | } | ||
1103 | |||
1048 | static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) | 1104 | static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) |
1049 | { | 1105 | { |
1050 | return atc_daio_unmute(atc, state, SPDIFOO); | 1106 | return atc_daio_unmute(atc, state, SPDIFOO); |
@@ -1331,17 +1387,20 @@ static int atc_get_resources(struct ct_atc *atc) | |||
1331 | struct srcimp_mgr *srcimp_mgr; | 1387 | struct srcimp_mgr *srcimp_mgr; |
1332 | struct sum_desc sum_dsc = {0}; | 1388 | struct sum_desc sum_dsc = {0}; |
1333 | struct sum_mgr *sum_mgr; | 1389 | struct sum_mgr *sum_mgr; |
1334 | int err, i; | 1390 | int err, i, num_srcs, num_daios; |
1391 | |||
1392 | num_daios = ((atc->model == CTSB1270) ? 8 : 7); | ||
1393 | num_srcs = ((atc->model == CTSB1270) ? 6 : 4); | ||
1335 | 1394 | ||
1336 | atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL); | 1395 | atc->daios = kzalloc(sizeof(void *)*num_daios, GFP_KERNEL); |
1337 | if (!atc->daios) | 1396 | if (!atc->daios) |
1338 | return -ENOMEM; | 1397 | return -ENOMEM; |
1339 | 1398 | ||
1340 | atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); | 1399 | atc->srcs = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL); |
1341 | if (!atc->srcs) | 1400 | if (!atc->srcs) |
1342 | return -ENOMEM; | 1401 | return -ENOMEM; |
1343 | 1402 | ||
1344 | atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); | 1403 | atc->srcimps = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL); |
1345 | if (!atc->srcimps) | 1404 | if (!atc->srcimps) |
1346 | return -ENOMEM; | 1405 | return -ENOMEM; |
1347 | 1406 | ||
@@ -1351,8 +1410,9 @@ static int atc_get_resources(struct ct_atc *atc) | |||
1351 | 1410 | ||
1352 | daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; | 1411 | daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; |
1353 | da_desc.msr = atc->msr; | 1412 | da_desc.msr = atc->msr; |
1354 | for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) { | 1413 | for (i = 0, atc->n_daio = 0; i < num_daios; i++) { |
1355 | da_desc.type = i; | 1414 | da_desc.type = (atc->model != CTSB073X) ? i : |
1415 | ((i == SPDIFIO) ? SPDIFI1 : i); | ||
1356 | err = daio_mgr->get_daio(daio_mgr, &da_desc, | 1416 | err = daio_mgr->get_daio(daio_mgr, &da_desc, |
1357 | (struct daio **)&atc->daios[i]); | 1417 | (struct daio **)&atc->daios[i]); |
1358 | if (err) { | 1418 | if (err) { |
@@ -1362,23 +1422,12 @@ static int atc_get_resources(struct ct_atc *atc) | |||
1362 | } | 1422 | } |
1363 | atc->n_daio++; | 1423 | atc->n_daio++; |
1364 | } | 1424 | } |
1365 | if (atc->model == CTSB073X) | ||
1366 | da_desc.type = SPDIFI1; | ||
1367 | else | ||
1368 | da_desc.type = SPDIFIO; | ||
1369 | err = daio_mgr->get_daio(daio_mgr, &da_desc, | ||
1370 | (struct daio **)&atc->daios[i]); | ||
1371 | if (err) { | ||
1372 | printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n"); | ||
1373 | return err; | ||
1374 | } | ||
1375 | atc->n_daio++; | ||
1376 | 1425 | ||
1377 | src_mgr = atc->rsc_mgrs[SRC]; | 1426 | src_mgr = atc->rsc_mgrs[SRC]; |
1378 | src_dsc.multi = 1; | 1427 | src_dsc.multi = 1; |
1379 | src_dsc.msr = atc->msr; | 1428 | src_dsc.msr = atc->msr; |
1380 | src_dsc.mode = ARCRW; | 1429 | src_dsc.mode = ARCRW; |
1381 | for (i = 0, atc->n_src = 0; i < (2*2); i++) { | 1430 | for (i = 0, atc->n_src = 0; i < num_srcs; i++) { |
1382 | err = src_mgr->get_src(src_mgr, &src_dsc, | 1431 | err = src_mgr->get_src(src_mgr, &src_dsc, |
1383 | (struct src **)&atc->srcs[i]); | 1432 | (struct src **)&atc->srcs[i]); |
1384 | if (err) | 1433 | if (err) |
@@ -1388,8 +1437,8 @@ static int atc_get_resources(struct ct_atc *atc) | |||
1388 | } | 1437 | } |
1389 | 1438 | ||
1390 | srcimp_mgr = atc->rsc_mgrs[SRCIMP]; | 1439 | srcimp_mgr = atc->rsc_mgrs[SRCIMP]; |
1391 | srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */ | 1440 | srcimp_dsc.msr = 8; |
1392 | for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) { | 1441 | for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) { |
1393 | err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, | 1442 | err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, |
1394 | (struct srcimp **)&atc->srcimps[i]); | 1443 | (struct srcimp **)&atc->srcimps[i]); |
1395 | if (err) | 1444 | if (err) |
@@ -1397,15 +1446,6 @@ static int atc_get_resources(struct ct_atc *atc) | |||
1397 | 1446 | ||
1398 | atc->n_srcimp++; | 1447 | atc->n_srcimp++; |
1399 | } | 1448 | } |
1400 | srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */ | ||
1401 | for (i = 0; i < (2*1); i++) { | ||
1402 | err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, | ||
1403 | (struct srcimp **)&atc->srcimps[2*1+i]); | ||
1404 | if (err) | ||
1405 | return err; | ||
1406 | |||
1407 | atc->n_srcimp++; | ||
1408 | } | ||
1409 | 1449 | ||
1410 | sum_mgr = atc->rsc_mgrs[SUM]; | 1450 | sum_mgr = atc->rsc_mgrs[SUM]; |
1411 | sum_dsc.msr = atc->msr; | 1451 | sum_dsc.msr = atc->msr; |
@@ -1488,6 +1528,18 @@ static void atc_connect_resources(struct ct_atc *atc) | |||
1488 | src = atc->srcs[3]; | 1528 | src = atc->srcs[3]; |
1489 | mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); | 1529 | mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); |
1490 | 1530 | ||
1531 | if (atc->model == CTSB1270) { | ||
1532 | /* Titanium HD has a dedicated ADC for the Mic. */ | ||
1533 | dai = container_of(atc->daios[MIC], struct dai, daio); | ||
1534 | atc_connect_dai(atc->rsc_mgrs[SRC], dai, | ||
1535 | (struct src **)&atc->srcs[4], | ||
1536 | (struct srcimp **)&atc->srcimps[4]); | ||
1537 | src = atc->srcs[4]; | ||
1538 | mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); | ||
1539 | src = atc->srcs[5]; | ||
1540 | mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); | ||
1541 | } | ||
1542 | |||
1491 | dai = container_of(atc->daios[SPDIFIO], struct dai, daio); | 1543 | dai = container_of(atc->daios[SPDIFIO], struct dai, daio); |
1492 | atc_connect_dai(atc->rsc_mgrs[SRC], dai, | 1544 | atc_connect_dai(atc->rsc_mgrs[SRC], dai, |
1493 | (struct src **)&atc->srcs[0], | 1545 | (struct src **)&atc->srcs[0], |
@@ -1606,12 +1658,20 @@ static struct ct_atc atc_preset __devinitdata = { | |||
1606 | .line_clfe_unmute = atc_line_clfe_unmute, | 1658 | .line_clfe_unmute = atc_line_clfe_unmute, |
1607 | .line_rear_unmute = atc_line_rear_unmute, | 1659 | .line_rear_unmute = atc_line_rear_unmute, |
1608 | .line_in_unmute = atc_line_in_unmute, | 1660 | .line_in_unmute = atc_line_in_unmute, |
1661 | .mic_unmute = atc_mic_unmute, | ||
1609 | .spdif_out_unmute = atc_spdif_out_unmute, | 1662 | .spdif_out_unmute = atc_spdif_out_unmute, |
1610 | .spdif_in_unmute = atc_spdif_in_unmute, | 1663 | .spdif_in_unmute = atc_spdif_in_unmute, |
1611 | .spdif_out_get_status = atc_spdif_out_get_status, | 1664 | .spdif_out_get_status = atc_spdif_out_get_status, |
1612 | .spdif_out_set_status = atc_spdif_out_set_status, | 1665 | .spdif_out_set_status = atc_spdif_out_set_status, |
1613 | .spdif_out_passthru = atc_spdif_out_passthru, | 1666 | .spdif_out_passthru = atc_spdif_out_passthru, |
1614 | .have_digit_io_switch = atc_have_digit_io_switch, | 1667 | .have_digit_io_switch = atc_have_digit_io_switch, |
1668 | .have_dedicated_mic = atc_have_dedicated_mic, | ||
1669 | .have_output_switch = atc_have_output_switch, | ||
1670 | .output_switch_get = atc_output_switch_get, | ||
1671 | .output_switch_put = atc_output_switch_put, | ||
1672 | .have_mic_source_switch = atc_have_mic_source_switch, | ||
1673 | .mic_source_switch_get = atc_mic_source_switch_get, | ||
1674 | .mic_source_switch_put = atc_mic_source_switch_put, | ||
1615 | #ifdef CONFIG_PM | 1675 | #ifdef CONFIG_PM |
1616 | .suspend = atc_suspend, | 1676 | .suspend = atc_suspend, |
1617 | .resume = atc_resume, | 1677 | .resume = atc_resume, |
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index 7167c0185d52..6bad27e06f4d 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h | |||
@@ -115,12 +115,20 @@ struct ct_atc { | |||
115 | int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state); | 115 | int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state); |
116 | int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state); | 116 | int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state); |
117 | int (*line_in_unmute)(struct ct_atc *atc, unsigned char state); | 117 | int (*line_in_unmute)(struct ct_atc *atc, unsigned char state); |
118 | int (*mic_unmute)(struct ct_atc *atc, unsigned char state); | ||
118 | int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state); | 119 | int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state); |
119 | int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state); | 120 | int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state); |
120 | int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status); | 121 | int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status); |
121 | int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status); | 122 | int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status); |
122 | int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state); | 123 | int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state); |
123 | int (*have_digit_io_switch)(struct ct_atc *atc); | 124 | int (*have_digit_io_switch)(struct ct_atc *atc); |
125 | int (*have_dedicated_mic)(struct ct_atc *atc); | ||
126 | int (*have_output_switch)(struct ct_atc *atc); | ||
127 | int (*output_switch_get)(struct ct_atc *atc); | ||
128 | int (*output_switch_put)(struct ct_atc *atc, int position); | ||
129 | int (*have_mic_source_switch)(struct ct_atc *atc); | ||
130 | int (*mic_source_switch_get)(struct ct_atc *atc); | ||
131 | int (*mic_source_switch_put)(struct ct_atc *atc, int position); | ||
124 | 132 | ||
125 | /* Don't touch! Used for internal object. */ | 133 | /* Don't touch! Used for internal object. */ |
126 | void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */ | 134 | void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */ |
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 47d9ea97de02..0c00eb4088ef 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c | |||
@@ -22,20 +22,9 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | 24 | ||
25 | #define DAIO_RESOURCE_NUM NUM_DAIOTYP | ||
26 | #define DAIO_OUT_MAX SPDIFOO | 25 | #define DAIO_OUT_MAX SPDIFOO |
27 | 26 | ||
28 | union daio_usage { | 27 | struct daio_usage { |
29 | struct { | ||
30 | unsigned short lineo1:1; | ||
31 | unsigned short lineo2:1; | ||
32 | unsigned short lineo3:1; | ||
33 | unsigned short lineo4:1; | ||
34 | unsigned short spdifoo:1; | ||
35 | unsigned short lineim:1; | ||
36 | unsigned short spdifio:1; | ||
37 | unsigned short spdifi1:1; | ||
38 | } bf; | ||
39 | unsigned short data; | 28 | unsigned short data; |
40 | }; | 29 | }; |
41 | 30 | ||
@@ -61,6 +50,7 @@ struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = { | |||
61 | [LINEO3] = {.left = 0x50, .right = 0x51}, | 50 | [LINEO3] = {.left = 0x50, .right = 0x51}, |
62 | [LINEO4] = {.left = 0x70, .right = 0x71}, | 51 | [LINEO4] = {.left = 0x70, .right = 0x71}, |
63 | [LINEIM] = {.left = 0x45, .right = 0xc5}, | 52 | [LINEIM] = {.left = 0x45, .right = 0xc5}, |
53 | [MIC] = {.left = 0x55, .right = 0xd5}, | ||
64 | [SPDIFOO] = {.left = 0x00, .right = 0x01}, | 54 | [SPDIFOO] = {.left = 0x00, .right = 0x01}, |
65 | [SPDIFIO] = {.left = 0x05, .right = 0x85}, | 55 | [SPDIFIO] = {.left = 0x05, .right = 0x85}, |
66 | }; | 56 | }; |
@@ -138,6 +128,7 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw) | |||
138 | case LINEO3: return 5; | 128 | case LINEO3: return 5; |
139 | case LINEO4: return 6; | 129 | case LINEO4: return 6; |
140 | case LINEIM: return 4; | 130 | case LINEIM: return 4; |
131 | case MIC: return 5; | ||
141 | default: return -EINVAL; | 132 | default: return -EINVAL; |
142 | } | 133 | } |
143 | default: | 134 | default: |
@@ -519,17 +510,17 @@ static int dai_rsc_uninit(struct dai *dai) | |||
519 | 510 | ||
520 | static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) | 511 | static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) |
521 | { | 512 | { |
522 | if (((union daio_usage *)mgr->rscs)->data & (0x1 << type)) | 513 | if (((struct daio_usage *)mgr->rscs)->data & (0x1 << type)) |
523 | return -ENOENT; | 514 | return -ENOENT; |
524 | 515 | ||
525 | ((union daio_usage *)mgr->rscs)->data |= (0x1 << type); | 516 | ((struct daio_usage *)mgr->rscs)->data |= (0x1 << type); |
526 | 517 | ||
527 | return 0; | 518 | return 0; |
528 | } | 519 | } |
529 | 520 | ||
530 | static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) | 521 | static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) |
531 | { | 522 | { |
532 | ((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type); | 523 | ((struct daio_usage *)mgr->rscs)->data &= ~(0x1 << type); |
533 | 524 | ||
534 | return 0; | 525 | return 0; |
535 | } | 526 | } |
@@ -712,7 +703,7 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr) | |||
712 | if (!daio_mgr) | 703 | if (!daio_mgr) |
713 | return -ENOMEM; | 704 | return -ENOMEM; |
714 | 705 | ||
715 | err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw); | 706 | err = rsc_mgr_init(&daio_mgr->mgr, DAIO, NUM_DAIOTYP, hw); |
716 | if (err) | 707 | if (err) |
717 | goto error1; | 708 | goto error1; |
718 | 709 | ||
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h index 0f52ce571ee8..85ccb6ee1ab4 100644 --- a/sound/pci/ctxfi/ctdaio.h +++ b/sound/pci/ctxfi/ctdaio.h | |||
@@ -33,6 +33,7 @@ enum DAIOTYP { | |||
33 | SPDIFOO, /* S/PDIF Out (Flexijack/Optical) */ | 33 | SPDIFOO, /* S/PDIF Out (Flexijack/Optical) */ |
34 | LINEIM, | 34 | LINEIM, |
35 | SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */ | 35 | SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */ |
36 | MIC, /* Dedicated mic on Titanium HD */ | ||
36 | SPDIFI1, /* S/PDIF In on internal Drive Bay */ | 37 | SPDIFI1, /* S/PDIF In on internal Drive Bay */ |
37 | NUM_DAIOTYP | 38 | NUM_DAIOTYP |
38 | }; | 39 | }; |
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h index af55405f5dec..de59bbf2702f 100644 --- a/sound/pci/ctxfi/cthardware.h +++ b/sound/pci/ctxfi/cthardware.h | |||
@@ -39,6 +39,7 @@ enum CTCARDS { | |||
39 | CT20K2_MODEL_FIRST = CTSB0760, | 39 | CT20K2_MODEL_FIRST = CTSB0760, |
40 | CTHENDRIX, | 40 | CTHENDRIX, |
41 | CTSB0880, | 41 | CTSB0880, |
42 | CTSB1270, | ||
42 | CT20K2_UNKNOWN, | 43 | CT20K2_UNKNOWN, |
43 | NUM_CTCARDS /* This should always be the last */ | 44 | NUM_CTCARDS /* This should always be the last */ |
44 | }; | 45 | }; |
@@ -71,6 +72,13 @@ struct hw { | |||
71 | int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source); | 72 | int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source); |
72 | int (*select_adc_source)(struct hw *hw, enum ADCSRC source); | 73 | int (*select_adc_source)(struct hw *hw, enum ADCSRC source); |
73 | int (*have_digit_io_switch)(struct hw *hw); | 74 | int (*have_digit_io_switch)(struct hw *hw); |
75 | int (*have_dedicated_mic)(struct hw *hw); | ||
76 | int (*have_output_switch)(struct hw *hw); | ||
77 | int (*output_switch_get)(struct hw *hw); | ||
78 | int (*output_switch_put)(struct hw *hw, int position); | ||
79 | int (*have_mic_source_switch)(struct hw *hw); | ||
80 | int (*mic_source_switch_get)(struct hw *hw); | ||
81 | int (*mic_source_switch_put)(struct hw *hw, int position); | ||
74 | 82 | ||
75 | /* SRC operations */ | 83 | /* SRC operations */ |
76 | int (*src_rsc_get_ctrl_blk)(void **rblk); | 84 | int (*src_rsc_get_ctrl_blk)(void **rblk); |
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index a5c957db5cea..9a85a84b23ab 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c | |||
@@ -1783,6 +1783,21 @@ static int hw_have_digit_io_switch(struct hw *hw) | |||
1783 | return !(hw->model == CTSB073X || hw->model == CTUAA); | 1783 | return !(hw->model == CTSB073X || hw->model == CTUAA); |
1784 | } | 1784 | } |
1785 | 1785 | ||
1786 | static int hw_have_dedicated_mic(struct hw *hw) | ||
1787 | { | ||
1788 | return 0; | ||
1789 | } | ||
1790 | |||
1791 | static int hw_have_output_switch(struct hw *hw) | ||
1792 | { | ||
1793 | return 0; | ||
1794 | } | ||
1795 | |||
1796 | static int hw_have_mic_source_switch(struct hw *hw) | ||
1797 | { | ||
1798 | return 0; | ||
1799 | } | ||
1800 | |||
1786 | #define CTLBITS(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) | 1801 | #define CTLBITS(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) |
1787 | 1802 | ||
1788 | #define UAA_CFG_PWRSTATUS 0x44 | 1803 | #define UAA_CFG_PWRSTATUS 0x44 |
@@ -2173,6 +2188,9 @@ static struct hw ct20k1_preset __devinitdata = { | |||
2173 | .is_adc_source_selected = hw_is_adc_input_selected, | 2188 | .is_adc_source_selected = hw_is_adc_input_selected, |
2174 | .select_adc_source = hw_adc_input_select, | 2189 | .select_adc_source = hw_adc_input_select, |
2175 | .have_digit_io_switch = hw_have_digit_io_switch, | 2190 | .have_digit_io_switch = hw_have_digit_io_switch, |
2191 | .have_dedicated_mic = hw_have_dedicated_mic, | ||
2192 | .have_output_switch = hw_have_output_switch, | ||
2193 | .have_mic_source_switch = hw_have_mic_source_switch, | ||
2176 | #ifdef CONFIG_PM | 2194 | #ifdef CONFIG_PM |
2177 | .suspend = hw_suspend, | 2195 | .suspend = hw_suspend, |
2178 | .resume = hw_resume, | 2196 | .resume = hw_resume, |
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 5364164674e4..8bc6e41ce64b 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * @File cthw20k2.c | 8 | * @File cthw20k2.c |
9 | * | 9 | * |
10 | * @Brief | 10 | * @Brief |
11 | * This file contains the implementation of hardware access methord for 20k2. | 11 | * This file contains the implementation of hardware access method for 20k2. |
12 | * | 12 | * |
13 | * @Author Liu Chun | 13 | * @Author Liu Chun |
14 | * @Date May 14 2008 | 14 | * @Date May 14 2008 |
@@ -38,6 +38,8 @@ struct hw20k2 { | |||
38 | unsigned char dev_id; | 38 | unsigned char dev_id; |
39 | unsigned char addr_size; | 39 | unsigned char addr_size; |
40 | unsigned char data_size; | 40 | unsigned char data_size; |
41 | |||
42 | int mic_source; | ||
41 | }; | 43 | }; |
42 | 44 | ||
43 | static u32 hw_read_20kx(struct hw *hw, u32 reg); | 45 | static u32 hw_read_20kx(struct hw *hw, u32 reg); |
@@ -1163,7 +1165,12 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) | |||
1163 | hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101); | 1165 | hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101); |
1164 | hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); | 1166 | hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); |
1165 | } else if (2 == info->msr) { | 1167 | } else if (2 == info->msr) { |
1166 | hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111); | 1168 | if (hw->model != CTSB1270) { |
1169 | hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111); | ||
1170 | } else { | ||
1171 | /* PCM4220 on Titanium HD is different. */ | ||
1172 | hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111); | ||
1173 | } | ||
1167 | /* Specify all playing 96khz | 1174 | /* Specify all playing 96khz |
1168 | * EA [0] - Enabled | 1175 | * EA [0] - Enabled |
1169 | * RTA [4:5] - 96kHz | 1176 | * RTA [4:5] - 96kHz |
@@ -1175,6 +1182,10 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) | |||
1175 | * RTD [28:29] - 96kHz */ | 1182 | * RTD [28:29] - 96kHz */ |
1176 | hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111); | 1183 | hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111); |
1177 | hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); | 1184 | hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); |
1185 | } else if ((4 == info->msr) && (hw->model == CTSB1270)) { | ||
1186 | hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111); | ||
1187 | hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121); | ||
1188 | hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); | ||
1178 | } else { | 1189 | } else { |
1179 | printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n"); | 1190 | printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n"); |
1180 | return -EINVAL; | 1191 | return -EINVAL; |
@@ -1182,6 +1193,8 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) | |||
1182 | 1193 | ||
1183 | for (i = 0; i < 8; i++) { | 1194 | for (i = 0; i < 8; i++) { |
1184 | if (i <= 3) { | 1195 | if (i <= 3) { |
1196 | /* This comment looks wrong since loop is over 4 */ | ||
1197 | /* channels and emu20k2 supports 4 spdif IOs. */ | ||
1185 | /* 1st 3 channels are SPDIFs (SB0960) */ | 1198 | /* 1st 3 channels are SPDIFs (SB0960) */ |
1186 | if (i == 3) | 1199 | if (i == 3) |
1187 | data = 0x1001001; | 1200 | data = 0x1001001; |
@@ -1206,12 +1219,16 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) | |||
1206 | 1219 | ||
1207 | hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B); | 1220 | hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B); |
1208 | } else { | 1221 | } else { |
1222 | /* Again, loop is over 4 channels not 5. */ | ||
1209 | /* Next 5 channels are I2S (SB0960) */ | 1223 | /* Next 5 channels are I2S (SB0960) */ |
1210 | data = 0x11; | 1224 | data = 0x11; |
1211 | hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data); | 1225 | hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data); |
1212 | if (2 == info->msr) { | 1226 | if (2 == info->msr) { |
1213 | /* Four channels per sample period */ | 1227 | /* Four channels per sample period */ |
1214 | data |= 0x1000; | 1228 | data |= 0x1000; |
1229 | } else if (4 == info->msr) { | ||
1230 | /* FIXME: check this against the chip spec */ | ||
1231 | data |= 0x2000; | ||
1215 | } | 1232 | } |
1216 | hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data); | 1233 | hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data); |
1217 | } | 1234 | } |
@@ -1557,7 +1574,7 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data) | |||
1557 | 1574 | ||
1558 | hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); | 1575 | hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); |
1559 | hw20k2_i2c_wait_data_ready(hw); | 1576 | hw20k2_i2c_wait_data_ready(hw); |
1560 | /* Dummy write to trigger the write oprtation */ | 1577 | /* Dummy write to trigger the write operation */ |
1561 | hw_write_20kx(hw, I2C_IF_WDATA, 0); | 1578 | hw_write_20kx(hw, I2C_IF_WDATA, 0); |
1562 | hw20k2_i2c_wait_data_ready(hw); | 1579 | hw20k2_i2c_wait_data_ready(hw); |
1563 | 1580 | ||
@@ -1568,6 +1585,30 @@ static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data) | |||
1568 | return 0; | 1585 | return 0; |
1569 | } | 1586 | } |
1570 | 1587 | ||
1588 | static void hw_dac_stop(struct hw *hw) | ||
1589 | { | ||
1590 | u32 data; | ||
1591 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1592 | data &= 0xFFFFFFFD; | ||
1593 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1594 | mdelay(10); | ||
1595 | } | ||
1596 | |||
1597 | static void hw_dac_start(struct hw *hw) | ||
1598 | { | ||
1599 | u32 data; | ||
1600 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1601 | data |= 0x2; | ||
1602 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1603 | mdelay(50); | ||
1604 | } | ||
1605 | |||
1606 | static void hw_dac_reset(struct hw *hw) | ||
1607 | { | ||
1608 | hw_dac_stop(hw); | ||
1609 | hw_dac_start(hw); | ||
1610 | } | ||
1611 | |||
1571 | static int hw_dac_init(struct hw *hw, const struct dac_conf *info) | 1612 | static int hw_dac_init(struct hw *hw, const struct dac_conf *info) |
1572 | { | 1613 | { |
1573 | int err; | 1614 | int err; |
@@ -1594,6 +1635,21 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info) | |||
1594 | 0x00000000 /* Vol Control B4 */ | 1635 | 0x00000000 /* Vol Control B4 */ |
1595 | }; | 1636 | }; |
1596 | 1637 | ||
1638 | if (hw->model == CTSB1270) { | ||
1639 | hw_dac_stop(hw); | ||
1640 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1641 | data &= ~0x0600; | ||
1642 | if (1 == info->msr) | ||
1643 | data |= 0x0000; /* Single Speed Mode 0-50kHz */ | ||
1644 | else if (2 == info->msr) | ||
1645 | data |= 0x0200; /* Double Speed Mode 50-100kHz */ | ||
1646 | else | ||
1647 | data |= 0x0600; /* Quad Speed Mode 100-200kHz */ | ||
1648 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1649 | hw_dac_start(hw); | ||
1650 | return 0; | ||
1651 | } | ||
1652 | |||
1597 | /* Set DAC reset bit as output */ | 1653 | /* Set DAC reset bit as output */ |
1598 | data = hw_read_20kx(hw, GPIO_CTRL); | 1654 | data = hw_read_20kx(hw, GPIO_CTRL); |
1599 | data |= 0x02; | 1655 | data |= 0x02; |
@@ -1606,22 +1662,8 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info) | |||
1606 | for (i = 0; i < 2; i++) { | 1662 | for (i = 0; i < 2; i++) { |
1607 | /* Reset DAC twice just in-case the chip | 1663 | /* Reset DAC twice just in-case the chip |
1608 | * didn't initialized properly */ | 1664 | * didn't initialized properly */ |
1609 | data = hw_read_20kx(hw, GPIO_DATA); | 1665 | hw_dac_reset(hw); |
1610 | /* GPIO data bit 1 */ | 1666 | hw_dac_reset(hw); |
1611 | data &= 0xFFFFFFFD; | ||
1612 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1613 | mdelay(10); | ||
1614 | data |= 0x2; | ||
1615 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1616 | mdelay(50); | ||
1617 | |||
1618 | /* Reset the 2nd time */ | ||
1619 | data &= 0xFFFFFFFD; | ||
1620 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1621 | mdelay(10); | ||
1622 | data |= 0x2; | ||
1623 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1624 | mdelay(50); | ||
1625 | 1667 | ||
1626 | if (hw20k2_i2c_read(hw, CS4382_MC1, &cs_read.mode_control_1)) | 1668 | if (hw20k2_i2c_read(hw, CS4382_MC1, &cs_read.mode_control_1)) |
1627 | continue; | 1669 | continue; |
@@ -1725,7 +1767,11 @@ End: | |||
1725 | static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) | 1767 | static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) |
1726 | { | 1768 | { |
1727 | u32 data; | 1769 | u32 data; |
1728 | 1770 | if (hw->model == CTSB1270) { | |
1771 | /* Titanium HD has two ADC chips, one for line in and one */ | ||
1772 | /* for MIC. We don't need to switch the ADC input. */ | ||
1773 | return 1; | ||
1774 | } | ||
1729 | data = hw_read_20kx(hw, GPIO_DATA); | 1775 | data = hw_read_20kx(hw, GPIO_DATA); |
1730 | switch (type) { | 1776 | switch (type) { |
1731 | case ADC_MICIN: | 1777 | case ADC_MICIN: |
@@ -1742,35 +1788,47 @@ static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) | |||
1742 | 1788 | ||
1743 | #define MIC_BOOST_0DB 0xCF | 1789 | #define MIC_BOOST_0DB 0xCF |
1744 | #define MIC_BOOST_STEPS_PER_DB 2 | 1790 | #define MIC_BOOST_STEPS_PER_DB 2 |
1745 | #define MIC_BOOST_20DB (MIC_BOOST_0DB + 20 * MIC_BOOST_STEPS_PER_DB) | 1791 | |
1792 | static void hw_wm8775_input_select(struct hw *hw, u8 input, s8 gain_in_db) | ||
1793 | { | ||
1794 | u32 adcmc, gain; | ||
1795 | |||
1796 | if (input > 3) | ||
1797 | input = 3; | ||
1798 | |||
1799 | adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */ | ||
1800 | |||
1801 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc), | ||
1802 | MAKE_WM8775_DATA(adcmc)); | ||
1803 | |||
1804 | if (gain_in_db < -103) | ||
1805 | gain_in_db = -103; | ||
1806 | if (gain_in_db > 24) | ||
1807 | gain_in_db = 24; | ||
1808 | |||
1809 | gain = gain_in_db * MIC_BOOST_STEPS_PER_DB + MIC_BOOST_0DB; | ||
1810 | |||
1811 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain), | ||
1812 | MAKE_WM8775_DATA(gain)); | ||
1813 | /* ...so there should be no need for the following. */ | ||
1814 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain), | ||
1815 | MAKE_WM8775_DATA(gain)); | ||
1816 | } | ||
1746 | 1817 | ||
1747 | static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) | 1818 | static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) |
1748 | { | 1819 | { |
1749 | u32 data; | 1820 | u32 data; |
1750 | |||
1751 | data = hw_read_20kx(hw, GPIO_DATA); | 1821 | data = hw_read_20kx(hw, GPIO_DATA); |
1752 | switch (type) { | 1822 | switch (type) { |
1753 | case ADC_MICIN: | 1823 | case ADC_MICIN: |
1754 | data |= (0x1 << 14); | 1824 | data |= (0x1 << 14); |
1755 | hw_write_20kx(hw, GPIO_DATA, data); | 1825 | hw_write_20kx(hw, GPIO_DATA, data); |
1756 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), | 1826 | hw_wm8775_input_select(hw, 0, 20); /* Mic, 20dB */ |
1757 | MAKE_WM8775_DATA(0x101)); /* Mic-in */ | ||
1758 | hw20k2_i2c_write(hw, | ||
1759 | MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB), | ||
1760 | MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ | ||
1761 | hw20k2_i2c_write(hw, | ||
1762 | MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB), | ||
1763 | MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ | ||
1764 | break; | 1827 | break; |
1765 | case ADC_LINEIN: | 1828 | case ADC_LINEIN: |
1766 | data &= ~(0x1 << 14); | 1829 | data &= ~(0x1 << 14); |
1767 | hw_write_20kx(hw, GPIO_DATA, data); | 1830 | hw_write_20kx(hw, GPIO_DATA, data); |
1768 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), | 1831 | hw_wm8775_input_select(hw, 1, 0); /* Line-in, 0dB */ |
1769 | MAKE_WM8775_DATA(0x102)); /* Line-in */ | ||
1770 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), | ||
1771 | MAKE_WM8775_DATA(0xCF)); /* No boost */ | ||
1772 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), | ||
1773 | MAKE_WM8775_DATA(0xCF)); /* No boost */ | ||
1774 | break; | 1832 | break; |
1775 | default: | 1833 | default: |
1776 | break; | 1834 | break; |
@@ -1782,7 +1840,7 @@ static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) | |||
1782 | static int hw_adc_init(struct hw *hw, const struct adc_conf *info) | 1840 | static int hw_adc_init(struct hw *hw, const struct adc_conf *info) |
1783 | { | 1841 | { |
1784 | int err; | 1842 | int err; |
1785 | u32 mux = 2, data, ctl; | 1843 | u32 data, ctl; |
1786 | 1844 | ||
1787 | /* Set ADC reset bit as output */ | 1845 | /* Set ADC reset bit as output */ |
1788 | data = hw_read_20kx(hw, GPIO_CTRL); | 1846 | data = hw_read_20kx(hw, GPIO_CTRL); |
@@ -1796,19 +1854,42 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) | |||
1796 | goto error; | 1854 | goto error; |
1797 | } | 1855 | } |
1798 | 1856 | ||
1799 | /* Make ADC in normal operation */ | 1857 | /* Reset the ADC (reset is active low). */ |
1800 | data = hw_read_20kx(hw, GPIO_DATA); | 1858 | data = hw_read_20kx(hw, GPIO_DATA); |
1801 | data &= ~(0x1 << 15); | 1859 | data &= ~(0x1 << 15); |
1860 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1861 | |||
1862 | if (hw->model == CTSB1270) { | ||
1863 | /* Set up the PCM4220 ADC on Titanium HD */ | ||
1864 | data &= ~0x0C; | ||
1865 | if (1 == info->msr) | ||
1866 | data |= 0x00; /* Single Speed Mode 32-50kHz */ | ||
1867 | else if (2 == info->msr) | ||
1868 | data |= 0x08; /* Double Speed Mode 50-108kHz */ | ||
1869 | else | ||
1870 | data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */ | ||
1871 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1872 | } | ||
1873 | |||
1802 | mdelay(10); | 1874 | mdelay(10); |
1875 | /* Return the ADC to normal operation. */ | ||
1803 | data |= (0x1 << 15); | 1876 | data |= (0x1 << 15); |
1804 | hw_write_20kx(hw, GPIO_DATA, data); | 1877 | hw_write_20kx(hw, GPIO_DATA, data); |
1805 | mdelay(50); | 1878 | mdelay(50); |
1806 | 1879 | ||
1880 | /* I2C write to register offset 0x0B to set ADC LRCLK polarity */ | ||
1881 | /* invert bit, interface format to I2S, word length to 24-bit, */ | ||
1882 | /* enable ADC high pass filter. Fixes bug 5323? */ | ||
1883 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26), | ||
1884 | MAKE_WM8775_DATA(0x26)); | ||
1885 | |||
1807 | /* Set the master mode (256fs) */ | 1886 | /* Set the master mode (256fs) */ |
1808 | if (1 == info->msr) { | 1887 | if (1 == info->msr) { |
1888 | /* slave mode, 128x oversampling 256fs */ | ||
1809 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02), | 1889 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02), |
1810 | MAKE_WM8775_DATA(0x02)); | 1890 | MAKE_WM8775_DATA(0x02)); |
1811 | } else if (2 == info->msr) { | 1891 | } else if ((2 == info->msr) || (4 == info->msr)) { |
1892 | /* slave mode, 64x oversampling, 256fs */ | ||
1812 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), | 1893 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), |
1813 | MAKE_WM8775_DATA(0x0A)); | 1894 | MAKE_WM8775_DATA(0x0A)); |
1814 | } else { | 1895 | } else { |
@@ -1818,47 +1899,17 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) | |||
1818 | goto error; | 1899 | goto error; |
1819 | } | 1900 | } |
1820 | 1901 | ||
1821 | /* Configure GPIO bit 14 change to line-in/mic-in */ | 1902 | if (hw->model != CTSB1270) { |
1822 | ctl = hw_read_20kx(hw, GPIO_CTRL); | 1903 | /* Configure GPIO bit 14 change to line-in/mic-in */ |
1823 | ctl |= 0x1 << 14; | 1904 | ctl = hw_read_20kx(hw, GPIO_CTRL); |
1824 | hw_write_20kx(hw, GPIO_CTRL, ctl); | 1905 | ctl |= 0x1 << 14; |
1825 | 1906 | hw_write_20kx(hw, GPIO_CTRL, ctl); | |
1826 | /* Check using Mic-in or Line-in */ | 1907 | hw_adc_input_select(hw, ADC_LINEIN); |
1827 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1828 | |||
1829 | if (mux == 1) { | ||
1830 | /* Configures GPIO data to select Mic-in */ | ||
1831 | data |= 0x1 << 14; | ||
1832 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1833 | |||
1834 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), | ||
1835 | MAKE_WM8775_DATA(0x101)); /* Mic-in */ | ||
1836 | hw20k2_i2c_write(hw, | ||
1837 | MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB), | ||
1838 | MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ | ||
1839 | hw20k2_i2c_write(hw, | ||
1840 | MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB), | ||
1841 | MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */ | ||
1842 | } else if (mux == 2) { | ||
1843 | /* Configures GPIO data to select Line-in */ | ||
1844 | data &= ~(0x1 << 14); | ||
1845 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1846 | |||
1847 | /* Setup ADC */ | ||
1848 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), | ||
1849 | MAKE_WM8775_DATA(0x102)); /* Line-in */ | ||
1850 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), | ||
1851 | MAKE_WM8775_DATA(0xCF)); /* No boost */ | ||
1852 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), | ||
1853 | MAKE_WM8775_DATA(0xCF)); /* No boost */ | ||
1854 | } else { | 1908 | } else { |
1855 | printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n"); | 1909 | hw_wm8775_input_select(hw, 0, 0); |
1856 | err = -EINVAL; | ||
1857 | goto error; | ||
1858 | } | 1910 | } |
1859 | 1911 | ||
1860 | return 0; | 1912 | return 0; |
1861 | |||
1862 | error: | 1913 | error: |
1863 | hw20k2_i2c_uninit(hw); | 1914 | hw20k2_i2c_uninit(hw); |
1864 | return err; | 1915 | return err; |
@@ -1869,6 +1920,102 @@ static int hw_have_digit_io_switch(struct hw *hw) | |||
1869 | return 0; | 1920 | return 0; |
1870 | } | 1921 | } |
1871 | 1922 | ||
1923 | static int hw_have_dedicated_mic(struct hw *hw) | ||
1924 | { | ||
1925 | return hw->model == CTSB1270; | ||
1926 | } | ||
1927 | |||
1928 | static int hw_have_output_switch(struct hw *hw) | ||
1929 | { | ||
1930 | return hw->model == CTSB1270; | ||
1931 | } | ||
1932 | |||
1933 | static int hw_output_switch_get(struct hw *hw) | ||
1934 | { | ||
1935 | u32 data = hw_read_20kx(hw, GPIO_EXT_DATA); | ||
1936 | |||
1937 | switch (data & 0x30) { | ||
1938 | case 0x00: | ||
1939 | return 0; | ||
1940 | case 0x10: | ||
1941 | return 1; | ||
1942 | case 0x20: | ||
1943 | return 2; | ||
1944 | default: | ||
1945 | return 3; | ||
1946 | } | ||
1947 | } | ||
1948 | |||
1949 | static int hw_output_switch_put(struct hw *hw, int position) | ||
1950 | { | ||
1951 | u32 data; | ||
1952 | |||
1953 | if (position == hw_output_switch_get(hw)) | ||
1954 | return 0; | ||
1955 | |||
1956 | /* Mute line and headphones (intended for anti-pop). */ | ||
1957 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1958 | data |= (0x03 << 11); | ||
1959 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1960 | |||
1961 | data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30; | ||
1962 | switch (position) { | ||
1963 | case 0: | ||
1964 | break; | ||
1965 | case 1: | ||
1966 | data |= 0x10; | ||
1967 | break; | ||
1968 | default: | ||
1969 | data |= 0x20; | ||
1970 | } | ||
1971 | hw_write_20kx(hw, GPIO_EXT_DATA, data); | ||
1972 | |||
1973 | /* Unmute line and headphones. */ | ||
1974 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1975 | data &= ~(0x03 << 11); | ||
1976 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1977 | |||
1978 | return 1; | ||
1979 | } | ||
1980 | |||
1981 | static int hw_have_mic_source_switch(struct hw *hw) | ||
1982 | { | ||
1983 | return hw->model == CTSB1270; | ||
1984 | } | ||
1985 | |||
1986 | static int hw_mic_source_switch_get(struct hw *hw) | ||
1987 | { | ||
1988 | struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; | ||
1989 | |||
1990 | return hw20k2->mic_source; | ||
1991 | } | ||
1992 | |||
1993 | static int hw_mic_source_switch_put(struct hw *hw, int position) | ||
1994 | { | ||
1995 | struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; | ||
1996 | |||
1997 | if (position == hw20k2->mic_source) | ||
1998 | return 0; | ||
1999 | |||
2000 | switch (position) { | ||
2001 | case 0: | ||
2002 | hw_wm8775_input_select(hw, 0, 0); /* Mic, 0dB */ | ||
2003 | break; | ||
2004 | case 1: | ||
2005 | hw_wm8775_input_select(hw, 1, 0); /* FP Mic, 0dB */ | ||
2006 | break; | ||
2007 | case 2: | ||
2008 | hw_wm8775_input_select(hw, 3, 0); /* Aux Ext, 0dB */ | ||
2009 | break; | ||
2010 | default: | ||
2011 | return 0; | ||
2012 | } | ||
2013 | |||
2014 | hw20k2->mic_source = position; | ||
2015 | |||
2016 | return 1; | ||
2017 | } | ||
2018 | |||
1872 | static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id) | 2019 | static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id) |
1873 | { | 2020 | { |
1874 | struct hw *hw = dev_id; | 2021 | struct hw *hw = dev_id; |
@@ -2023,13 +2170,16 @@ static int hw_card_init(struct hw *hw, struct card_conf *info) | |||
2023 | /* Reset all SRC pending interrupts */ | 2170 | /* Reset all SRC pending interrupts */ |
2024 | hw_write_20kx(hw, SRC_IP, 0); | 2171 | hw_write_20kx(hw, SRC_IP, 0); |
2025 | 2172 | ||
2026 | /* TODO: detect the card ID and configure GPIO accordingly. */ | 2173 | if (hw->model != CTSB1270) { |
2027 | /* Configures GPIO (0xD802 0x98028) */ | 2174 | /* TODO: detect the card ID and configure GPIO accordingly. */ |
2028 | /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/ | 2175 | /* Configures GPIO (0xD802 0x98028) */ |
2029 | /* Configures GPIO (SB0880) */ | 2176 | /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/ |
2030 | /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/ | 2177 | /* Configures GPIO (SB0880) */ |
2031 | hw_write_20kx(hw, GPIO_CTRL, 0xD802); | 2178 | /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/ |
2032 | 2179 | hw_write_20kx(hw, GPIO_CTRL, 0xD802); | |
2180 | } else { | ||
2181 | hw_write_20kx(hw, GPIO_CTRL, 0x9E5F); | ||
2182 | } | ||
2033 | /* Enable audio ring */ | 2183 | /* Enable audio ring */ |
2034 | hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01); | 2184 | hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01); |
2035 | 2185 | ||
@@ -2107,6 +2257,13 @@ static struct hw ct20k2_preset __devinitdata = { | |||
2107 | .is_adc_source_selected = hw_is_adc_input_selected, | 2257 | .is_adc_source_selected = hw_is_adc_input_selected, |
2108 | .select_adc_source = hw_adc_input_select, | 2258 | .select_adc_source = hw_adc_input_select, |
2109 | .have_digit_io_switch = hw_have_digit_io_switch, | 2259 | .have_digit_io_switch = hw_have_digit_io_switch, |
2260 | .have_dedicated_mic = hw_have_dedicated_mic, | ||
2261 | .have_output_switch = hw_have_output_switch, | ||
2262 | .output_switch_get = hw_output_switch_get, | ||
2263 | .output_switch_put = hw_output_switch_put, | ||
2264 | .have_mic_source_switch = hw_have_mic_source_switch, | ||
2265 | .mic_source_switch_get = hw_mic_source_switch_get, | ||
2266 | .mic_source_switch_put = hw_mic_source_switch_put, | ||
2110 | #ifdef CONFIG_PM | 2267 | #ifdef CONFIG_PM |
2111 | .suspend = hw_suspend, | 2268 | .suspend = hw_suspend, |
2112 | .resume = hw_resume, | 2269 | .resume = hw_resume, |
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index c3519ff42fbb..388235c43789 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c | |||
@@ -86,9 +86,7 @@ enum CTALSA_MIXER_CTL { | |||
86 | MIXER_LINEIN_C_S, | 86 | MIXER_LINEIN_C_S, |
87 | MIXER_MIC_C_S, | 87 | MIXER_MIC_C_S, |
88 | MIXER_SPDIFI_C_S, | 88 | MIXER_SPDIFI_C_S, |
89 | MIXER_LINEIN_P_S, | ||
90 | MIXER_SPDIFO_P_S, | 89 | MIXER_SPDIFO_P_S, |
91 | MIXER_SPDIFI_P_S, | ||
92 | MIXER_WAVEF_P_S, | 90 | MIXER_WAVEF_P_S, |
93 | MIXER_WAVER_P_S, | 91 | MIXER_WAVER_P_S, |
94 | MIXER_WAVEC_P_S, | 92 | MIXER_WAVEC_P_S, |
@@ -137,11 +135,11 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { | |||
137 | }, | 135 | }, |
138 | [MIXER_LINEIN_P] = { | 136 | [MIXER_LINEIN_P] = { |
139 | .ctl = 1, | 137 | .ctl = 1, |
140 | .name = "Line-in Playback Volume", | 138 | .name = "Line Playback Volume", |
141 | }, | 139 | }, |
142 | [MIXER_LINEIN_C] = { | 140 | [MIXER_LINEIN_C] = { |
143 | .ctl = 1, | 141 | .ctl = 1, |
144 | .name = "Line-in Capture Volume", | 142 | .name = "Line Capture Volume", |
145 | }, | 143 | }, |
146 | [MIXER_MIC_P] = { | 144 | [MIXER_MIC_P] = { |
147 | .ctl = 1, | 145 | .ctl = 1, |
@@ -153,15 +151,15 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { | |||
153 | }, | 151 | }, |
154 | [MIXER_SPDIFI_P] = { | 152 | [MIXER_SPDIFI_P] = { |
155 | .ctl = 1, | 153 | .ctl = 1, |
156 | .name = "S/PDIF-in Playback Volume", | 154 | .name = "IEC958 Playback Volume", |
157 | }, | 155 | }, |
158 | [MIXER_SPDIFI_C] = { | 156 | [MIXER_SPDIFI_C] = { |
159 | .ctl = 1, | 157 | .ctl = 1, |
160 | .name = "S/PDIF-in Capture Volume", | 158 | .name = "IEC958 Capture Volume", |
161 | }, | 159 | }, |
162 | [MIXER_SPDIFO_P] = { | 160 | [MIXER_SPDIFO_P] = { |
163 | .ctl = 1, | 161 | .ctl = 1, |
164 | .name = "S/PDIF-out Playback Volume", | 162 | .name = "Digital Playback Volume", |
165 | }, | 163 | }, |
166 | [MIXER_WAVEF_P] = { | 164 | [MIXER_WAVEF_P] = { |
167 | .ctl = 1, | 165 | .ctl = 1, |
@@ -179,14 +177,13 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { | |||
179 | .ctl = 1, | 177 | .ctl = 1, |
180 | .name = "Surround Playback Volume", | 178 | .name = "Surround Playback Volume", |
181 | }, | 179 | }, |
182 | |||
183 | [MIXER_PCM_C_S] = { | 180 | [MIXER_PCM_C_S] = { |
184 | .ctl = 1, | 181 | .ctl = 1, |
185 | .name = "PCM Capture Switch", | 182 | .name = "PCM Capture Switch", |
186 | }, | 183 | }, |
187 | [MIXER_LINEIN_C_S] = { | 184 | [MIXER_LINEIN_C_S] = { |
188 | .ctl = 1, | 185 | .ctl = 1, |
189 | .name = "Line-in Capture Switch", | 186 | .name = "Line Capture Switch", |
190 | }, | 187 | }, |
191 | [MIXER_MIC_C_S] = { | 188 | [MIXER_MIC_C_S] = { |
192 | .ctl = 1, | 189 | .ctl = 1, |
@@ -194,19 +191,11 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { | |||
194 | }, | 191 | }, |
195 | [MIXER_SPDIFI_C_S] = { | 192 | [MIXER_SPDIFI_C_S] = { |
196 | .ctl = 1, | 193 | .ctl = 1, |
197 | .name = "S/PDIF-in Capture Switch", | 194 | .name = "IEC958 Capture Switch", |
198 | }, | ||
199 | [MIXER_LINEIN_P_S] = { | ||
200 | .ctl = 1, | ||
201 | .name = "Line-in Playback Switch", | ||
202 | }, | 195 | }, |
203 | [MIXER_SPDIFO_P_S] = { | 196 | [MIXER_SPDIFO_P_S] = { |
204 | .ctl = 1, | 197 | .ctl = 1, |
205 | .name = "S/PDIF-out Playback Switch", | 198 | .name = "Digital Playback Switch", |
206 | }, | ||
207 | [MIXER_SPDIFI_P_S] = { | ||
208 | .ctl = 1, | ||
209 | .name = "S/PDIF-in Playback Switch", | ||
210 | }, | 199 | }, |
211 | [MIXER_WAVEF_P_S] = { | 200 | [MIXER_WAVEF_P_S] = { |
212 | .ctl = 1, | 201 | .ctl = 1, |
@@ -236,6 +225,8 @@ ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); | |||
236 | static void | 225 | static void |
237 | ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); | 226 | ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); |
238 | 227 | ||
228 | /* FIXME: this static looks like it would fail if more than one card was */ | ||
229 | /* installed. */ | ||
239 | static struct snd_kcontrol *kctls[2] = {NULL}; | 230 | static struct snd_kcontrol *kctls[2] = {NULL}; |
240 | 231 | ||
241 | static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index) | 232 | static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index) |
@@ -420,6 +411,77 @@ static struct snd_kcontrol_new vol_ctl = { | |||
420 | .tlv = { .p = ct_vol_db_scale }, | 411 | .tlv = { .p = ct_vol_db_scale }, |
421 | }; | 412 | }; |
422 | 413 | ||
414 | static int output_switch_info(struct snd_kcontrol *kcontrol, | ||
415 | struct snd_ctl_elem_info *info) | ||
416 | { | ||
417 | static const char *const names[3] = { | ||
418 | "FP Headphones", "Headphones", "Speakers" | ||
419 | }; | ||
420 | |||
421 | return snd_ctl_enum_info(info, 1, 3, names); | ||
422 | } | ||
423 | |||
424 | static int output_switch_get(struct snd_kcontrol *kcontrol, | ||
425 | struct snd_ctl_elem_value *ucontrol) | ||
426 | { | ||
427 | struct ct_atc *atc = snd_kcontrol_chip(kcontrol); | ||
428 | ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc); | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int output_switch_put(struct snd_kcontrol *kcontrol, | ||
433 | struct snd_ctl_elem_value *ucontrol) | ||
434 | { | ||
435 | struct ct_atc *atc = snd_kcontrol_chip(kcontrol); | ||
436 | if (ucontrol->value.enumerated.item[0] > 2) | ||
437 | return -EINVAL; | ||
438 | return atc->output_switch_put(atc, ucontrol->value.enumerated.item[0]); | ||
439 | } | ||
440 | |||
441 | static struct snd_kcontrol_new output_ctl = { | ||
442 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
443 | .name = "Analog Output Playback Enum", | ||
444 | .info = output_switch_info, | ||
445 | .get = output_switch_get, | ||
446 | .put = output_switch_put, | ||
447 | }; | ||
448 | |||
449 | static int mic_source_switch_info(struct snd_kcontrol *kcontrol, | ||
450 | struct snd_ctl_elem_info *info) | ||
451 | { | ||
452 | static const char *const names[3] = { | ||
453 | "Mic", "FP Mic", "Aux" | ||
454 | }; | ||
455 | |||
456 | return snd_ctl_enum_info(info, 1, 3, names); | ||
457 | } | ||
458 | |||
459 | static int mic_source_switch_get(struct snd_kcontrol *kcontrol, | ||
460 | struct snd_ctl_elem_value *ucontrol) | ||
461 | { | ||
462 | struct ct_atc *atc = snd_kcontrol_chip(kcontrol); | ||
463 | ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static int mic_source_switch_put(struct snd_kcontrol *kcontrol, | ||
468 | struct snd_ctl_elem_value *ucontrol) | ||
469 | { | ||
470 | struct ct_atc *atc = snd_kcontrol_chip(kcontrol); | ||
471 | if (ucontrol->value.enumerated.item[0] > 2) | ||
472 | return -EINVAL; | ||
473 | return atc->mic_source_switch_put(atc, | ||
474 | ucontrol->value.enumerated.item[0]); | ||
475 | } | ||
476 | |||
477 | static struct snd_kcontrol_new mic_source_ctl = { | ||
478 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
479 | .name = "Mic Source Capture Enum", | ||
480 | .info = mic_source_switch_info, | ||
481 | .get = mic_source_switch_get, | ||
482 | .put = mic_source_switch_put, | ||
483 | }; | ||
484 | |||
423 | static void | 485 | static void |
424 | do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type) | 486 | do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type) |
425 | { | 487 | { |
@@ -465,6 +527,7 @@ do_digit_io_switch(struct ct_atc *atc, int state) | |||
465 | static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) | 527 | static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) |
466 | { | 528 | { |
467 | struct ct_mixer *mixer = atc->mixer; | 529 | struct ct_mixer *mixer = atc->mixer; |
530 | int have_dedicated_mic = atc->have_dedicated_mic(atc); | ||
468 | 531 | ||
469 | /* Do changes in mixer. */ | 532 | /* Do changes in mixer. */ |
470 | if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) { | 533 | if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) { |
@@ -477,8 +540,17 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) | |||
477 | } | 540 | } |
478 | } | 541 | } |
479 | /* Do changes out of mixer. */ | 542 | /* Do changes out of mixer. */ |
480 | if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) | 543 | if (!have_dedicated_mic && |
481 | do_line_mic_switch(atc, type); | 544 | (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) { |
545 | if (state) | ||
546 | do_line_mic_switch(atc, type); | ||
547 | atc->line_in_unmute(atc, state); | ||
548 | } else if (have_dedicated_mic && (MIXER_LINEIN_C_S == type)) | ||
549 | atc->line_in_unmute(atc, state); | ||
550 | else if (have_dedicated_mic && (MIXER_MIC_C_S == type)) | ||
551 | atc->mic_unmute(atc, state); | ||
552 | else if (MIXER_SPDIFI_C_S == type) | ||
553 | atc->spdif_in_unmute(atc, state); | ||
482 | else if (MIXER_WAVEF_P_S == type) | 554 | else if (MIXER_WAVEF_P_S == type) |
483 | atc->line_front_unmute(atc, state); | 555 | atc->line_front_unmute(atc, state); |
484 | else if (MIXER_WAVES_P_S == type) | 556 | else if (MIXER_WAVES_P_S == type) |
@@ -487,12 +559,8 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) | |||
487 | atc->line_clfe_unmute(atc, state); | 559 | atc->line_clfe_unmute(atc, state); |
488 | else if (MIXER_WAVER_P_S == type) | 560 | else if (MIXER_WAVER_P_S == type) |
489 | atc->line_rear_unmute(atc, state); | 561 | atc->line_rear_unmute(atc, state); |
490 | else if (MIXER_LINEIN_P_S == type) | ||
491 | atc->line_in_unmute(atc, state); | ||
492 | else if (MIXER_SPDIFO_P_S == type) | 562 | else if (MIXER_SPDIFO_P_S == type) |
493 | atc->spdif_out_unmute(atc, state); | 563 | atc->spdif_out_unmute(atc, state); |
494 | else if (MIXER_SPDIFI_P_S == type) | ||
495 | atc->spdif_in_unmute(atc, state); | ||
496 | else if (MIXER_DIGITAL_IO_S == type) | 564 | else if (MIXER_DIGITAL_IO_S == type) |
497 | do_digit_io_switch(atc, state); | 565 | do_digit_io_switch(atc, state); |
498 | 566 | ||
@@ -686,6 +754,7 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) | |||
686 | 754 | ||
687 | ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = | 755 | ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = |
688 | atc->have_digit_io_switch(atc); | 756 | atc->have_digit_io_switch(atc); |
757 | |||
689 | for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) { | 758 | for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) { |
690 | if (ct_kcontrol_init_table[type].ctl) { | 759 | if (ct_kcontrol_init_table[type].ctl) { |
691 | swh_ctl.name = ct_kcontrol_init_table[type].name; | 760 | swh_ctl.name = ct_kcontrol_init_table[type].name; |
@@ -708,6 +777,17 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) | |||
708 | if (err) | 777 | if (err) |
709 | return err; | 778 | return err; |
710 | 779 | ||
780 | if (atc->have_output_switch(atc)) { | ||
781 | err = ct_mixer_kcontrol_new(mixer, &output_ctl); | ||
782 | if (err) | ||
783 | return err; | ||
784 | } | ||
785 | |||
786 | if (atc->have_mic_source_switch(atc)) { | ||
787 | err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl); | ||
788 | if (err) | ||
789 | return err; | ||
790 | } | ||
711 | atc->line_front_unmute(atc, 1); | 791 | atc->line_front_unmute(atc, 1); |
712 | set_switch_state(mixer, MIXER_WAVEF_P_S, 1); | 792 | set_switch_state(mixer, MIXER_WAVEF_P_S, 1); |
713 | atc->line_surround_unmute(atc, 0); | 793 | atc->line_surround_unmute(atc, 0); |
@@ -719,13 +799,12 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) | |||
719 | atc->spdif_out_unmute(atc, 0); | 799 | atc->spdif_out_unmute(atc, 0); |
720 | set_switch_state(mixer, MIXER_SPDIFO_P_S, 0); | 800 | set_switch_state(mixer, MIXER_SPDIFO_P_S, 0); |
721 | atc->line_in_unmute(atc, 0); | 801 | atc->line_in_unmute(atc, 0); |
722 | set_switch_state(mixer, MIXER_LINEIN_P_S, 0); | 802 | if (atc->have_dedicated_mic(atc)) |
803 | atc->mic_unmute(atc, 0); | ||
723 | atc->spdif_in_unmute(atc, 0); | 804 | atc->spdif_in_unmute(atc, 0); |
724 | set_switch_state(mixer, MIXER_SPDIFI_P_S, 0); | 805 | set_switch_state(mixer, MIXER_PCM_C_S, 0); |
725 | 806 | set_switch_state(mixer, MIXER_LINEIN_C_S, 0); | |
726 | set_switch_state(mixer, MIXER_PCM_C_S, 1); | 807 | set_switch_state(mixer, MIXER_SPDIFI_C_S, 0); |
727 | set_switch_state(mixer, MIXER_LINEIN_C_S, 1); | ||
728 | set_switch_state(mixer, MIXER_SPDIFI_C_S, 1); | ||
729 | 808 | ||
730 | return 0; | 809 | return 0; |
731 | } | 810 | } |
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index f42e7e1a1074..7afa765afa3c 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c | |||
@@ -80,11 +80,11 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
80 | "are 48000 and 44100, Value 48000 is assumed.\n"); | 80 | "are 48000 and 44100, Value 48000 is assumed.\n"); |
81 | reference_rate = 48000; | 81 | reference_rate = 48000; |
82 | } | 82 | } |
83 | if ((multiple != 1) && (multiple != 2)) { | 83 | if ((multiple != 1) && (multiple != 2) && (multiple != 4)) { |
84 | printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n", | 84 | printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n", |
85 | multiple); | 85 | multiple); |
86 | printk(KERN_ERR "ctxfi: The valid values for multiple are " | 86 | printk(KERN_ERR "ctxfi: The valid values for multiple are " |
87 | "1 and 2, Value 2 is assumed.\n"); | 87 | "1, 2 and 4, Value 2 is assumed.\n"); |
88 | multiple = 2; | 88 | multiple = 2; |
89 | } | 89 | } |
90 | err = ct_atc_create(card, pci, reference_rate, multiple, | 90 | err = ct_atc_create(card, pci, reference_rate, multiple, |