diff options
Diffstat (limited to 'sound/pci/ac97/ac97_patch.c')
-rw-r--r-- | sound/pci/ac97/ac97_patch.c | 585 |
1 files changed, 382 insertions, 203 deletions
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 13c34a5d8206..a15eb8522b7c 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -64,6 +64,116 @@ static int ac97_update_bits_page(ac97_t *ac97, unsigned short reg, unsigned shor | |||
64 | return ret; | 64 | return ret; |
65 | } | 65 | } |
66 | 66 | ||
67 | /* | ||
68 | * shared line-in/mic controls | ||
69 | */ | ||
70 | static int ac97_enum_text_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo, | ||
71 | const char **texts, unsigned int nums) | ||
72 | { | ||
73 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
74 | uinfo->count = 1; | ||
75 | uinfo->value.enumerated.items = nums; | ||
76 | if (uinfo->value.enumerated.item > nums - 1) | ||
77 | uinfo->value.enumerated.item = nums - 1; | ||
78 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int ac97_surround_jack_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
83 | { | ||
84 | static const char *texts[] = { "Shared", "Independent" }; | ||
85 | return ac97_enum_text_info(kcontrol, uinfo, texts, 2); | ||
86 | } | ||
87 | |||
88 | static int ac97_surround_jack_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
89 | { | ||
90 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
91 | |||
92 | ucontrol->value.enumerated.item[0] = ac97->indep_surround; | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int ac97_surround_jack_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
97 | { | ||
98 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
99 | unsigned char indep = !!ucontrol->value.enumerated.item[0]; | ||
100 | |||
101 | if (indep != ac97->indep_surround) { | ||
102 | ac97->indep_surround = indep; | ||
103 | if (ac97->build_ops->update_jacks) | ||
104 | ac97->build_ops->update_jacks(ac97); | ||
105 | return 1; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int ac97_channel_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
111 | { | ||
112 | static const char *texts[] = { "2ch", "4ch", "6ch" }; | ||
113 | if (kcontrol->private_value) | ||
114 | return ac97_enum_text_info(kcontrol, uinfo, texts, 2); /* 4ch only */ | ||
115 | return ac97_enum_text_info(kcontrol, uinfo, texts, 3); | ||
116 | } | ||
117 | |||
118 | static int ac97_channel_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
119 | { | ||
120 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
121 | |||
122 | ucontrol->value.enumerated.item[0] = ac97->channel_mode; | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int ac97_channel_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
127 | { | ||
128 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
129 | unsigned char mode = ucontrol->value.enumerated.item[0]; | ||
130 | |||
131 | if (mode != ac97->channel_mode) { | ||
132 | ac97->channel_mode = mode; | ||
133 | if (ac97->build_ops->update_jacks) | ||
134 | ac97->build_ops->update_jacks(ac97); | ||
135 | return 1; | ||
136 | } | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | #define AC97_SURROUND_JACK_MODE_CTL \ | ||
141 | { \ | ||
142 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
143 | .name = "Surround Jack Mode", \ | ||
144 | .info = ac97_surround_jack_mode_info, \ | ||
145 | .get = ac97_surround_jack_mode_get, \ | ||
146 | .put = ac97_surround_jack_mode_put, \ | ||
147 | } | ||
148 | #define AC97_CHANNEL_MODE_CTL \ | ||
149 | { \ | ||
150 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
151 | .name = "Channel Mode", \ | ||
152 | .info = ac97_channel_mode_info, \ | ||
153 | .get = ac97_channel_mode_get, \ | ||
154 | .put = ac97_channel_mode_put, \ | ||
155 | } | ||
156 | #define AC97_CHANNEL_MODE_4CH_CTL \ | ||
157 | { \ | ||
158 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
159 | .name = "Channel Mode", \ | ||
160 | .info = ac97_channel_mode_info, \ | ||
161 | .get = ac97_channel_mode_get, \ | ||
162 | .put = ac97_channel_mode_put, \ | ||
163 | .private_value = 1, \ | ||
164 | } | ||
165 | |||
166 | static inline int is_shared_linein(ac97_t *ac97) | ||
167 | { | ||
168 | return ! ac97->indep_surround && ac97->channel_mode >= 1; | ||
169 | } | ||
170 | |||
171 | static inline int is_shared_micin(ac97_t *ac97) | ||
172 | { | ||
173 | return ! ac97->indep_surround && ac97->channel_mode >= 2; | ||
174 | } | ||
175 | |||
176 | |||
67 | /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ | 177 | /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ |
68 | 178 | ||
69 | /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ | 179 | /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ |
@@ -1390,6 +1500,16 @@ static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_va | |||
1390 | AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); | 1500 | AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); |
1391 | } | 1501 | } |
1392 | 1502 | ||
1503 | static void ad1888_update_jacks(ac97_t *ac97) | ||
1504 | { | ||
1505 | /* shared Line-In */ | ||
1506 | snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, | ||
1507 | is_shared_linein(ac97) ? 0 : 1 << 12); | ||
1508 | /* shared Mic */ | ||
1509 | snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, | ||
1510 | is_shared_micin(ac97) ? 0 : 1 << 11); | ||
1511 | } | ||
1512 | |||
1393 | static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { | 1513 | static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { |
1394 | { | 1514 | { |
1395 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1406,8 +1526,8 @@ static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { | |||
1406 | .get = snd_ac97_ad1888_downmix_get, | 1526 | .get = snd_ac97_ad1888_downmix_get, |
1407 | .put = snd_ac97_ad1888_downmix_put | 1527 | .put = snd_ac97_ad1888_downmix_put |
1408 | }, | 1528 | }, |
1409 | AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), | 1529 | AC97_SURROUND_JACK_MODE_CTL, |
1410 | AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), | 1530 | AC97_CHANNEL_MODE_CTL, |
1411 | }; | 1531 | }; |
1412 | 1532 | ||
1413 | static int patch_ad1888_specific(ac97_t *ac97) | 1533 | static int patch_ad1888_specific(ac97_t *ac97) |
@@ -1422,8 +1542,9 @@ static struct snd_ac97_build_ops patch_ad1888_build_ops = { | |||
1422 | .build_post_spdif = patch_ad198x_post_spdif, | 1542 | .build_post_spdif = patch_ad198x_post_spdif, |
1423 | .build_specific = patch_ad1888_specific, | 1543 | .build_specific = patch_ad1888_specific, |
1424 | #ifdef CONFIG_PM | 1544 | #ifdef CONFIG_PM |
1425 | .resume = ad18xx_resume | 1545 | .resume = ad18xx_resume, |
1426 | #endif | 1546 | #endif |
1547 | .update_jacks = ad1888_update_jacks, | ||
1427 | }; | 1548 | }; |
1428 | 1549 | ||
1429 | int patch_ad1888(ac97_t * ac97) | 1550 | int patch_ad1888(ac97_t * ac97) |
@@ -1459,8 +1580,9 @@ static struct snd_ac97_build_ops patch_ad1980_build_ops = { | |||
1459 | .build_post_spdif = patch_ad198x_post_spdif, | 1580 | .build_post_spdif = patch_ad198x_post_spdif, |
1460 | .build_specific = patch_ad1980_specific, | 1581 | .build_specific = patch_ad1980_specific, |
1461 | #ifdef CONFIG_PM | 1582 | #ifdef CONFIG_PM |
1462 | .resume = ad18xx_resume | 1583 | .resume = ad18xx_resume, |
1463 | #endif | 1584 | #endif |
1585 | .update_jacks = ad1888_update_jacks, | ||
1464 | }; | 1586 | }; |
1465 | 1587 | ||
1466 | int patch_ad1980(ac97_t * ac97) | 1588 | int patch_ad1980(ac97_t * ac97) |
@@ -1471,10 +1593,21 @@ int patch_ad1980(ac97_t * ac97) | |||
1471 | } | 1593 | } |
1472 | 1594 | ||
1473 | static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { | 1595 | static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { |
1474 | AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0), | ||
1475 | AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) | 1596 | AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) |
1476 | }; | 1597 | }; |
1477 | 1598 | ||
1599 | static void ad1985_update_jacks(ac97_t *ac97) | ||
1600 | { | ||
1601 | /* shared Line-In */ | ||
1602 | snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, | ||
1603 | is_shared_linein(ac97) ? 0 : 1 << 12); | ||
1604 | /* shared Mic */ | ||
1605 | snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, | ||
1606 | is_shared_micin(ac97) ? 0 : 1 << 11); | ||
1607 | snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 1 << 9, | ||
1608 | is_shared_micin(ac97) ? 0 : 1 << 9); | ||
1609 | } | ||
1610 | |||
1478 | static int patch_ad1985_specific(ac97_t *ac97) | 1611 | static int patch_ad1985_specific(ac97_t *ac97) |
1479 | { | 1612 | { |
1480 | int err; | 1613 | int err; |
@@ -1488,8 +1621,9 @@ static struct snd_ac97_build_ops patch_ad1985_build_ops = { | |||
1488 | .build_post_spdif = patch_ad198x_post_spdif, | 1621 | .build_post_spdif = patch_ad198x_post_spdif, |
1489 | .build_specific = patch_ad1985_specific, | 1622 | .build_specific = patch_ad1985_specific, |
1490 | #ifdef CONFIG_PM | 1623 | #ifdef CONFIG_PM |
1491 | .resume = ad18xx_resume | 1624 | .resume = ad18xx_resume, |
1492 | #endif | 1625 | #endif |
1626 | .update_jacks = ad1985_update_jacks, | ||
1493 | }; | 1627 | }; |
1494 | 1628 | ||
1495 | int patch_ad1985(ac97_t * ac97) | 1629 | int patch_ad1985(ac97_t * ac97) |
@@ -1521,31 +1655,25 @@ int patch_ad1985(ac97_t * ac97) | |||
1521 | /* | 1655 | /* |
1522 | * realtek ALC65x/850 codecs | 1656 | * realtek ALC65x/850 codecs |
1523 | */ | 1657 | */ |
1524 | static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | 1658 | static void alc650_update_jacks(ac97_t *ac97) |
1525 | { | ||
1526 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1527 | ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; | ||
1528 | return 0; | ||
1529 | } | ||
1530 | |||
1531 | static int snd_ac97_alc650_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1532 | { | 1659 | { |
1533 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 1660 | int shared; |
1534 | int change, val; | 1661 | |
1535 | val = !!(snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10)); | 1662 | /* shared Line-In */ |
1536 | change = (ucontrol->value.integer.value[0] != val); | 1663 | shared = is_shared_linein(ac97); |
1537 | if (change) { | 1664 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9, |
1538 | /* disable/enable vref */ | 1665 | shared ? (1 << 9) : 0); |
1539 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, | 1666 | /* update shared Mic */ |
1540 | ucontrol->value.integer.value[0] ? (1 << 12) : 0); | 1667 | shared = is_shared_micin(ac97); |
1541 | /* turn on/off center-on-mic */ | 1668 | /* disable/enable vref */ |
1542 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, | 1669 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, |
1543 | ucontrol->value.integer.value[0] ? (1 << 10) : 0); | 1670 | shared ? (1 << 12) : 0); |
1544 | /* GPIO0 high for mic */ | 1671 | /* turn on/off center-on-mic */ |
1545 | snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, | 1672 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, |
1546 | ucontrol->value.integer.value[0] ? 0 : 0x100); | 1673 | shared ? (1 << 10) : 0); |
1547 | } | 1674 | /* GPIO0 high for mic */ |
1548 | return change; | 1675 | snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, |
1676 | shared ? 0 : 0x100); | ||
1549 | } | 1677 | } |
1550 | 1678 | ||
1551 | static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { | 1679 | static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { |
@@ -1558,8 +1686,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { | |||
1558 | /* 6: Independent Master Volume Right */ | 1686 | /* 6: Independent Master Volume Right */ |
1559 | /* 7: Independent Master Volume Left */ | 1687 | /* 7: Independent Master Volume Left */ |
1560 | /* 8: reserved */ | 1688 | /* 8: reserved */ |
1561 | AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), | 1689 | /* 9: Line-In/Surround share */ |
1562 | /* 10: mic, see below */ | 1690 | /* 10: Mic/CLFE share */ |
1563 | /* 11-13: in IEC958 controls */ | 1691 | /* 11-13: in IEC958 controls */ |
1564 | AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), | 1692 | AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), |
1565 | #if 0 /* always set in patch_alc650 */ | 1693 | #if 0 /* always set in patch_alc650 */ |
@@ -1570,14 +1698,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { | |||
1570 | AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), | 1698 | AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), |
1571 | AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), | 1699 | AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), |
1572 | #endif | 1700 | #endif |
1573 | { | 1701 | AC97_SURROUND_JACK_MODE_CTL, |
1574 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1702 | AC97_CHANNEL_MODE_CTL, |
1575 | .name = "Mic As Center/LFE", | ||
1576 | .info = snd_ac97_info_volsw, | ||
1577 | .get = snd_ac97_alc650_mic_get, | ||
1578 | .put = snd_ac97_alc650_mic_put, | ||
1579 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1580 | }, | ||
1581 | }; | 1703 | }; |
1582 | 1704 | ||
1583 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { | 1705 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { |
@@ -1601,7 +1723,8 @@ static int patch_alc650_specific(ac97_t * ac97) | |||
1601 | } | 1723 | } |
1602 | 1724 | ||
1603 | static struct snd_ac97_build_ops patch_alc650_ops = { | 1725 | static struct snd_ac97_build_ops patch_alc650_ops = { |
1604 | .build_specific = patch_alc650_specific | 1726 | .build_specific = patch_alc650_specific, |
1727 | .update_jacks = alc650_update_jacks | ||
1605 | }; | 1728 | }; |
1606 | 1729 | ||
1607 | int patch_alc650(ac97_t * ac97) | 1730 | int patch_alc650(ac97_t * ac97) |
@@ -1659,37 +1782,27 @@ int patch_alc650(ac97_t * ac97) | |||
1659 | return 0; | 1782 | return 0; |
1660 | } | 1783 | } |
1661 | 1784 | ||
1662 | static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | 1785 | static void alc655_update_jacks(ac97_t *ac97) |
1663 | { | ||
1664 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1665 | ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; | ||
1666 | return 0; | ||
1667 | } | ||
1668 | |||
1669 | static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1670 | { | 1786 | { |
1671 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 1787 | int shared; |
1672 | 1788 | ||
1789 | /* shared Line-In */ | ||
1790 | shared = is_shared_linein(ac97); | ||
1791 | ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9, | ||
1792 | shared ? (1 << 9) : 0, 0); | ||
1793 | /* update shared mic */ | ||
1794 | shared = is_shared_micin(ac97); | ||
1673 | /* misc control; vrefout disable */ | 1795 | /* misc control; vrefout disable */ |
1674 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, | 1796 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, |
1675 | ucontrol->value.integer.value[0] ? (1 << 12) : 0); | 1797 | shared ? (1 << 12) : 0); |
1676 | return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, | 1798 | ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, |
1677 | ucontrol->value.integer.value[0] ? (1 << 10) : 0, | 1799 | shared ? (1 << 10) : 0, 0); |
1678 | 0); | ||
1679 | } | 1800 | } |
1680 | 1801 | ||
1681 | |||
1682 | static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { | 1802 | static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { |
1683 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), | 1803 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), |
1684 | AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 0), | 1804 | AC97_SURROUND_JACK_MODE_CTL, |
1685 | { | 1805 | AC97_CHANNEL_MODE_CTL, |
1686 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1687 | .name = "Mic As Center/LFE", | ||
1688 | .info = snd_ac97_info_volsw, | ||
1689 | .get = snd_ac97_alc655_mic_get, | ||
1690 | .put = snd_ac97_alc655_mic_put, | ||
1691 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1692 | }, | ||
1693 | }; | 1806 | }; |
1694 | 1807 | ||
1695 | static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | 1808 | static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) |
@@ -1759,7 +1872,8 @@ static int patch_alc655_specific(ac97_t * ac97) | |||
1759 | } | 1872 | } |
1760 | 1873 | ||
1761 | static struct snd_ac97_build_ops patch_alc655_ops = { | 1874 | static struct snd_ac97_build_ops patch_alc655_ops = { |
1762 | .build_specific = patch_alc655_specific | 1875 | .build_specific = patch_alc655_specific, |
1876 | .update_jacks = alc655_update_jacks | ||
1763 | }; | 1877 | }; |
1764 | 1878 | ||
1765 | int patch_alc655(ac97_t * ac97) | 1879 | int patch_alc655(ac97_t * ac97) |
@@ -1798,63 +1912,33 @@ int patch_alc655(ac97_t * ac97) | |||
1798 | #define AC97_ALC850_JACK_SELECT 0x76 | 1912 | #define AC97_ALC850_JACK_SELECT 0x76 |
1799 | #define AC97_ALC850_MISC1 0x7a | 1913 | #define AC97_ALC850_MISC1 0x7a |
1800 | 1914 | ||
1801 | static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | 1915 | static void alc850_update_jacks(ac97_t *ac97) |
1802 | { | ||
1803 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1804 | ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 12) & 7) == 2; | ||
1805 | return 0; | ||
1806 | } | ||
1807 | |||
1808 | static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1809 | { | 1916 | { |
1810 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 1917 | int shared; |
1811 | 1918 | ||
1919 | /* shared Line-In */ | ||
1920 | shared = is_shared_linein(ac97); | ||
1812 | /* SURR 1kOhm (bit4), Amp (bit5) */ | 1921 | /* SURR 1kOhm (bit4), Amp (bit5) */ |
1813 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), | 1922 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), |
1814 | ucontrol->value.integer.value[0] ? (1<<5) : (1<<4)); | 1923 | shared ? (1<<5) : (1<<4)); |
1815 | /* LINE-IN = 0, SURROUND = 2 */ | 1924 | /* LINE-IN = 0, SURROUND = 2 */ |
1816 | return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, | 1925 | snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, |
1817 | ucontrol->value.integer.value[0] ? (2<<12) : (0<<12)); | 1926 | shared ? (2<<12) : (0<<12)); |
1818 | } | 1927 | /* update shared mic */ |
1819 | 1928 | shared = is_shared_micin(ac97); | |
1820 | static int ac97_alc850_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1821 | { | ||
1822 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1823 | ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 4) & 7) == 2; | ||
1824 | return 0; | ||
1825 | } | ||
1826 | |||
1827 | static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1828 | { | ||
1829 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1830 | |||
1831 | /* Vref disable (bit12), 1kOhm (bit13) */ | 1929 | /* Vref disable (bit12), 1kOhm (bit13) */ |
1832 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), | 1930 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), |
1833 | ucontrol->value.integer.value[0] ? (1<<12) : (1<<13)); | 1931 | shared ? (1<<12) : (1<<13)); |
1834 | /* MIC-IN = 1, CENTER-LFE = 2 */ | 1932 | /* MIC-IN = 1, CENTER-LFE = 2 */ |
1835 | return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, | 1933 | snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, |
1836 | ucontrol->value.integer.value[0] ? (2<<4) : (1<<4)); | 1934 | shared ? (2<<4) : (1<<4)); |
1837 | } | 1935 | } |
1838 | 1936 | ||
1839 | static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { | 1937 | static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { |
1840 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), | 1938 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), |
1841 | { | 1939 | AC97_SINGLE("Mic Front Input Switch", AC97_ALC850_JACK_SELECT, 15, 1, 1), |
1842 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1940 | AC97_SURROUND_JACK_MODE_CTL, |
1843 | .name = "Line-In As Surround", | 1941 | AC97_CHANNEL_MODE_CTL, |
1844 | .info = snd_ac97_info_volsw, | ||
1845 | .get = ac97_alc850_surround_get, | ||
1846 | .put = ac97_alc850_surround_put, | ||
1847 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1848 | }, | ||
1849 | { | ||
1850 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1851 | .name = "Mic As Center/LFE", | ||
1852 | .info = snd_ac97_info_volsw, | ||
1853 | .get = ac97_alc850_mic_get, | ||
1854 | .put = ac97_alc850_mic_put, | ||
1855 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1856 | }, | ||
1857 | |||
1858 | }; | 1942 | }; |
1859 | 1943 | ||
1860 | static int patch_alc850_specific(ac97_t *ac97) | 1944 | static int patch_alc850_specific(ac97_t *ac97) |
@@ -1871,7 +1955,8 @@ static int patch_alc850_specific(ac97_t *ac97) | |||
1871 | } | 1955 | } |
1872 | 1956 | ||
1873 | static struct snd_ac97_build_ops patch_alc850_ops = { | 1957 | static struct snd_ac97_build_ops patch_alc850_ops = { |
1874 | .build_specific = patch_alc850_specific | 1958 | .build_specific = patch_alc850_specific, |
1959 | .update_jacks = alc850_update_jacks | ||
1875 | }; | 1960 | }; |
1876 | 1961 | ||
1877 | int patch_alc850(ac97_t *ac97) | 1962 | int patch_alc850(ac97_t *ac97) |
@@ -1911,9 +1996,17 @@ int patch_alc850(ac97_t *ac97) | |||
1911 | /* | 1996 | /* |
1912 | * C-Media CM97xx codecs | 1997 | * C-Media CM97xx codecs |
1913 | */ | 1998 | */ |
1999 | static void cm9738_update_jacks(ac97_t *ac97) | ||
2000 | { | ||
2001 | /* shared Line-In */ | ||
2002 | snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10, | ||
2003 | is_shared_linein(ac97) ? (1 << 10) : 0); | ||
2004 | } | ||
2005 | |||
1914 | static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { | 2006 | static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { |
1915 | AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), | ||
1916 | AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), | 2007 | AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), |
2008 | AC97_SURROUND_JACK_MODE_CTL, | ||
2009 | AC97_CHANNEL_MODE_4CH_CTL, | ||
1917 | }; | 2010 | }; |
1918 | 2011 | ||
1919 | static int patch_cm9738_specific(ac97_t * ac97) | 2012 | static int patch_cm9738_specific(ac97_t * ac97) |
@@ -1922,7 +2015,8 @@ static int patch_cm9738_specific(ac97_t * ac97) | |||
1922 | } | 2015 | } |
1923 | 2016 | ||
1924 | static struct snd_ac97_build_ops patch_cm9738_ops = { | 2017 | static struct snd_ac97_build_ops patch_cm9738_ops = { |
1925 | .build_specific = patch_cm9738_specific | 2018 | .build_specific = patch_cm9738_specific, |
2019 | .update_jacks = cm9738_update_jacks | ||
1926 | }; | 2020 | }; |
1927 | 2021 | ||
1928 | int patch_cm9738(ac97_t * ac97) | 2022 | int patch_cm9738(ac97_t * ac97) |
@@ -1986,34 +2080,19 @@ static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = { | |||
1986 | /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ | 2080 | /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ |
1987 | }; | 2081 | }; |
1988 | 2082 | ||
1989 | static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2083 | static void cm9739_update_jacks(ac97_t *ac97) |
1990 | { | ||
1991 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1992 | if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) | ||
1993 | ucontrol->value.integer.value[0] = 1; | ||
1994 | else | ||
1995 | ucontrol->value.integer.value[0] = 0; | ||
1996 | return 0; | ||
1997 | } | ||
1998 | |||
1999 | static int snd_ac97_cm9739_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
2000 | { | 2084 | { |
2001 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2085 | /* shared Line-In */ |
2002 | return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, | 2086 | snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10, |
2003 | ucontrol->value.integer.value[0] ? | 2087 | is_shared_linein(ac97) ? (1 << 10) : 0); |
2004 | 0x1000 : 0x2000); | 2088 | /* shared Mic */ |
2089 | snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, | ||
2090 | is_shared_micin(ac97) ? 0x1000 : 0x2000); | ||
2005 | } | 2091 | } |
2006 | 2092 | ||
2007 | static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { | 2093 | static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { |
2008 | AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0), | 2094 | AC97_SURROUND_JACK_MODE_CTL, |
2009 | { | 2095 | AC97_CHANNEL_MODE_CTL, |
2010 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2011 | .name = "Mic As Center/LFE", | ||
2012 | .info = snd_ac97_info_volsw, | ||
2013 | .get = snd_ac97_cm9739_center_mic_get, | ||
2014 | .put = snd_ac97_cm9739_center_mic_put, | ||
2015 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
2016 | }, | ||
2017 | }; | 2096 | }; |
2018 | 2097 | ||
2019 | static int patch_cm9739_specific(ac97_t * ac97) | 2098 | static int patch_cm9739_specific(ac97_t * ac97) |
@@ -2028,7 +2107,8 @@ static int patch_cm9739_post_spdif(ac97_t * ac97) | |||
2028 | 2107 | ||
2029 | static struct snd_ac97_build_ops patch_cm9739_ops = { | 2108 | static struct snd_ac97_build_ops patch_cm9739_ops = { |
2030 | .build_specific = patch_cm9739_specific, | 2109 | .build_specific = patch_cm9739_specific, |
2031 | .build_post_spdif = patch_cm9739_post_spdif | 2110 | .build_post_spdif = patch_cm9739_post_spdif, |
2111 | .update_jacks = cm9739_update_jacks | ||
2032 | }; | 2112 | }; |
2033 | 2113 | ||
2034 | int patch_cm9739(ac97_t * ac97) | 2114 | int patch_cm9739(ac97_t * ac97) |
@@ -2087,71 +2167,97 @@ int patch_cm9739(ac97_t * ac97) | |||
2087 | } | 2167 | } |
2088 | 2168 | ||
2089 | #define AC97_CM9761_MULTI_CHAN 0x64 | 2169 | #define AC97_CM9761_MULTI_CHAN 0x64 |
2170 | #define AC97_CM9761_FUNC 0x66 | ||
2090 | #define AC97_CM9761_SPDIF_CTRL 0x6c | 2171 | #define AC97_CM9761_SPDIF_CTRL 0x6c |
2091 | 2172 | ||
2092 | static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2173 | static void cm9761_update_jacks(ac97_t *ac97) |
2093 | { | ||
2094 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
2095 | if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x0400) | ||
2096 | ucontrol->value.integer.value[0] = 1; | ||
2097 | else | ||
2098 | ucontrol->value.integer.value[0] = 0; | ||
2099 | return 0; | ||
2100 | } | ||
2101 | |||
2102 | static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
2103 | { | 2174 | { |
2104 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2175 | unsigned short surr_vals[2][2] = { |
2105 | unsigned short vals[2][2] = { | ||
2106 | { 0x0008, 0x0400 }, /* off, on */ | 2176 | { 0x0008, 0x0400 }, /* off, on */ |
2107 | { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ | 2177 | { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ |
2108 | }; | 2178 | }; |
2109 | return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x0408, | 2179 | unsigned short clfe_vals[2][2] = { |
2110 | vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); | 2180 | { 0x2000, 0x1880 }, /* off, on */ |
2181 | { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ | ||
2182 | }; | ||
2183 | |||
2184 | /* shared Line-In */ | ||
2185 | snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, | ||
2186 | surr_vals[ac97->spec.dev_flags][is_shared_linein(ac97)]); | ||
2187 | /* shared Mic */ | ||
2188 | snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, | ||
2189 | clfe_vals[ac97->spec.dev_flags][is_shared_micin(ac97)]); | ||
2190 | } | ||
2191 | |||
2192 | static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { | ||
2193 | AC97_SURROUND_JACK_MODE_CTL, | ||
2194 | AC97_CHANNEL_MODE_CTL, | ||
2195 | }; | ||
2196 | |||
2197 | static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
2198 | { | ||
2199 | static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" }; | ||
2200 | |||
2201 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2202 | uinfo->count = 1; | ||
2203 | uinfo->value.enumerated.items = 3; | ||
2204 | if (uinfo->value.enumerated.item > 2) | ||
2205 | uinfo->value.enumerated.item = 2; | ||
2206 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
2207 | return 0; | ||
2111 | } | 2208 | } |
2112 | 2209 | ||
2113 | static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2210 | static int cm9761_spdif_out_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
2114 | { | 2211 | { |
2115 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2212 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
2116 | if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) | 2213 | |
2117 | ucontrol->value.integer.value[0] = 1; | 2214 | if (ac97->regs[AC97_CM9761_FUNC] & 0x1) |
2215 | ucontrol->value.enumerated.item[0] = 2; /* SPDIF-loopback */ | ||
2216 | else if (ac97->regs[AC97_CM9761_SPDIF_CTRL] & 0x2) | ||
2217 | ucontrol->value.enumerated.item[0] = 1; /* ADC loopback */ | ||
2118 | else | 2218 | else |
2119 | ucontrol->value.integer.value[0] = 0; | 2219 | ucontrol->value.enumerated.item[0] = 0; /* AC-link */ |
2120 | if (ac97->spec.dev_flags) /* 9761-82 rev.B */ | ||
2121 | ucontrol->value.integer.value[0] = !ucontrol->value.integer.value[0]; | ||
2122 | return 0; | 2220 | return 0; |
2123 | } | 2221 | } |
2124 | 2222 | ||
2125 | static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2223 | static int cm9761_spdif_out_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
2126 | { | 2224 | { |
2127 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2225 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
2128 | unsigned short vals[2][2] = { | 2226 | |
2129 | { 0x2000, 0x1880 }, /* off, on */ | 2227 | if (ucontrol->value.enumerated.item[0] == 2) |
2130 | { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ | 2228 | return snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0x1); |
2131 | }; | 2229 | snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0); |
2132 | return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3880, | 2230 | return snd_ac97_update_bits(ac97, AC97_CM9761_SPDIF_CTRL, 0x2, |
2133 | vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); | 2231 | ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0); |
2134 | } | 2232 | } |
2135 | 2233 | ||
2136 | static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { | 2234 | static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" }; |
2137 | { | 2235 | static const struct ac97_enum cm9761_dac_clock_enum = |
2138 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2236 | AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock); |
2139 | .name = "Line-In As Surround", | 2237 | |
2140 | .info = snd_ac97_info_volsw, | 2238 | static const snd_kcontrol_new_t snd_ac97_cm9761_controls_spdif[] = { |
2141 | .get = snd_ac97_cm9761_linein_rear_get, | 2239 | { /* BIT 1: SPDIFS */ |
2142 | .put = snd_ac97_cm9761_linein_rear_put, | 2240 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2143 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | 2241 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
2144 | }, | 2242 | .info = cm9761_spdif_out_source_info, |
2145 | { | 2243 | .get = cm9761_spdif_out_source_get, |
2146 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2244 | .put = cm9761_spdif_out_source_put, |
2147 | .name = "Mic As Center/LFE", | ||
2148 | .info = snd_ac97_info_volsw, | ||
2149 | .get = snd_ac97_cm9761_center_mic_get, | ||
2150 | .put = snd_ac97_cm9761_center_mic_put, | ||
2151 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
2152 | }, | 2245 | }, |
2246 | /* BIT 2: IG_SPIV */ | ||
2247 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9761_SPDIF_CTRL, 2, 1, 0), | ||
2248 | /* BIT 3: SPI2F */ | ||
2249 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9761_SPDIF_CTRL, 3, 1, 0), | ||
2250 | /* BIT 4: SPI2SDI */ | ||
2251 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9761_SPDIF_CTRL, 4, 1, 0), | ||
2252 | /* BIT 9-10: DAC_CTL */ | ||
2253 | AC97_ENUM("DAC Clock Source", cm9761_dac_clock_enum), | ||
2153 | }; | 2254 | }; |
2154 | 2255 | ||
2256 | static int patch_cm9761_post_spdif(ac97_t * ac97) | ||
2257 | { | ||
2258 | return patch_build_controls(ac97, snd_ac97_cm9761_controls_spdif, ARRAY_SIZE(snd_ac97_cm9761_controls_spdif)); | ||
2259 | } | ||
2260 | |||
2155 | static int patch_cm9761_specific(ac97_t * ac97) | 2261 | static int patch_cm9761_specific(ac97_t * ac97) |
2156 | { | 2262 | { |
2157 | return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); | 2263 | return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); |
@@ -2159,7 +2265,8 @@ static int patch_cm9761_specific(ac97_t * ac97) | |||
2159 | 2265 | ||
2160 | static struct snd_ac97_build_ops patch_cm9761_ops = { | 2266 | static struct snd_ac97_build_ops patch_cm9761_ops = { |
2161 | .build_specific = patch_cm9761_specific, | 2267 | .build_specific = patch_cm9761_specific, |
2162 | .build_post_spdif = patch_cm9739_post_spdif /* hope it's identical... */ | 2268 | .build_post_spdif = patch_cm9761_post_spdif, |
2269 | .update_jacks = cm9761_update_jacks | ||
2163 | }; | 2270 | }; |
2164 | 2271 | ||
2165 | int patch_cm9761(ac97_t *ac97) | 2272 | int patch_cm9761(ac97_t *ac97) |
@@ -2193,24 +2300,25 @@ int patch_cm9761(ac97_t *ac97) | |||
2193 | /* to be sure: we overwrite the ext status bits */ | 2300 | /* to be sure: we overwrite the ext status bits */ |
2194 | snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0); | 2301 | snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0); |
2195 | /* Don't set 0x0200 here. This results in the silent analog output */ | 2302 | /* Don't set 0x0200 here. This results in the silent analog output */ |
2196 | snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0009); | 2303 | snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0001); /* enable spdif-in */ |
2197 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ | 2304 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ |
2198 | 2305 | ||
2199 | /* set-up multi channel */ | 2306 | /* set-up multi channel */ |
2200 | /* bit 15: pc master beep off | 2307 | /* bit 15: pc master beep off |
2201 | * bit 14: ?? | 2308 | * bit 14: pin47 = EAPD/SPDIF |
2202 | * bit 13: vref ctl [= cm9739] | 2309 | * bit 13: vref ctl [= cm9739] |
2203 | * bit 12: center/mic [= cm9739] (reverted on rev B) | 2310 | * bit 12: CLFE control (reverted on rev B) |
2204 | * bit 11: ?? (mic/center/lfe) (reverted on rev B) | 2311 | * bit 11: Mic/center share (reverted on rev B) |
2205 | * bit 10: suddound/line [= cm9739] | 2312 | * bit 10: suddound/line share |
2206 | * bit 9: mix 2 surround | 2313 | * bit 9: Analog-in mix -> surround |
2207 | * bit 8: ? | 2314 | * bit 8: Analog-in mix -> CLFE |
2208 | * bit 7: ?? (mic/center/lfe) | 2315 | * bit 7: Mic/LFE share (mic/center/lfe) |
2209 | * bit 4: ?? (front) | 2316 | * bit 5: vref select (9761A) |
2210 | * bit 3: ?? (line-in/rear share) (revereted with rev B) | 2317 | * bit 4: front control |
2211 | * bit 2: ?? (surround) | 2318 | * bit 3: surround control (revereted with rev B) |
2212 | * bit 1: front mic | 2319 | * bit 2: front mic |
2213 | * bit 0: mic boost | 2320 | * bit 1: stereo mic |
2321 | * bit 0: mic boost level (0=20dB, 1=30dB) | ||
2214 | */ | 2322 | */ |
2215 | 2323 | ||
2216 | #if 0 | 2324 | #if 0 |
@@ -2230,6 +2338,47 @@ int patch_cm9761(ac97_t *ac97) | |||
2230 | return 0; | 2338 | return 0; |
2231 | } | 2339 | } |
2232 | 2340 | ||
2341 | #define AC97_CM9780_SIDE 0x60 | ||
2342 | #define AC97_CM9780_JACK 0x62 | ||
2343 | #define AC97_CM9780_MIXER 0x64 | ||
2344 | #define AC97_CM9780_MULTI_CHAN 0x66 | ||
2345 | #define AC97_CM9780_SPDIF 0x6c | ||
2346 | |||
2347 | static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" }; | ||
2348 | static const struct ac97_enum cm9780_ch_select_enum = | ||
2349 | AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select); | ||
2350 | static const snd_kcontrol_new_t cm9780_controls[] = { | ||
2351 | AC97_DOUBLE("Side Playback Switch", AC97_CM9780_SIDE, 15, 7, 1, 1), | ||
2352 | AC97_DOUBLE("Side Playback Volume", AC97_CM9780_SIDE, 8, 0, 31, 0), | ||
2353 | AC97_ENUM("Side Playback Route", cm9780_ch_select_enum), | ||
2354 | }; | ||
2355 | |||
2356 | static int patch_cm9780_specific(ac97_t *ac97) | ||
2357 | { | ||
2358 | return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls)); | ||
2359 | } | ||
2360 | |||
2361 | static struct snd_ac97_build_ops patch_cm9780_ops = { | ||
2362 | .build_specific = patch_cm9780_specific, | ||
2363 | .build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */ | ||
2364 | }; | ||
2365 | |||
2366 | int patch_cm9780(ac97_t *ac97) | ||
2367 | { | ||
2368 | unsigned short val; | ||
2369 | |||
2370 | ac97->build_ops = &patch_cm9780_ops; | ||
2371 | |||
2372 | /* enable spdif */ | ||
2373 | if (ac97->ext_id & AC97_EI_SPDIF) { | ||
2374 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ | ||
2375 | val = snd_ac97_read(ac97, AC97_CM9780_SPDIF); | ||
2376 | val |= 0x1; /* SPDI_EN */ | ||
2377 | snd_ac97_write_cache(ac97, AC97_CM9780_SPDIF, val); | ||
2378 | } | ||
2379 | |||
2380 | return 0; | ||
2381 | } | ||
2233 | 2382 | ||
2234 | /* | 2383 | /* |
2235 | * VIA VT1616 codec | 2384 | * VIA VT1616 codec |
@@ -2263,9 +2412,21 @@ int patch_vt1616(ac97_t * ac97) | |||
2263 | return 0; | 2412 | return 0; |
2264 | } | 2413 | } |
2265 | 2414 | ||
2415 | /* | ||
2416 | */ | ||
2417 | static void it2646_update_jacks(ac97_t *ac97) | ||
2418 | { | ||
2419 | /* shared Line-In */ | ||
2420 | snd_ac97_update_bits(ac97, 0x76, 1 << 9, | ||
2421 | is_shared_linein(ac97) ? (1<<9) : 0); | ||
2422 | /* shared Mic */ | ||
2423 | snd_ac97_update_bits(ac97, 0x76, 1 << 10, | ||
2424 | is_shared_micin(ac97) ? (1<<10) : 0); | ||
2425 | } | ||
2426 | |||
2266 | static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { | 2427 | static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { |
2267 | AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0), | 2428 | AC97_SURROUND_JACK_MODE_CTL, |
2268 | AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0), | 2429 | AC97_CHANNEL_MODE_CTL, |
2269 | }; | 2430 | }; |
2270 | 2431 | ||
2271 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { | 2432 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { |
@@ -2285,7 +2446,8 @@ static int patch_it2646_specific(ac97_t * ac97) | |||
2285 | } | 2446 | } |
2286 | 2447 | ||
2287 | static struct snd_ac97_build_ops patch_it2646_ops = { | 2448 | static struct snd_ac97_build_ops patch_it2646_ops = { |
2288 | .build_specific = patch_it2646_specific | 2449 | .build_specific = patch_it2646_specific, |
2450 | .update_jacks = it2646_update_jacks | ||
2289 | }; | 2451 | }; |
2290 | 2452 | ||
2291 | int patch_it2646(ac97_t * ac97) | 2453 | int patch_it2646(ac97_t * ac97) |
@@ -2297,12 +2459,29 @@ int patch_it2646(ac97_t * ac97) | |||
2297 | return 0; | 2459 | return 0; |
2298 | } | 2460 | } |
2299 | 2461 | ||
2300 | /* Si3036/8 specific registers */ | 2462 | /* |
2463 | * Si3036 codec | ||
2464 | */ | ||
2465 | |||
2301 | #define AC97_SI3036_CHIP_ID 0x5a | 2466 | #define AC97_SI3036_CHIP_ID 0x5a |
2467 | #define AC97_SI3036_LINE_CFG 0x5c | ||
2468 | |||
2469 | static const snd_kcontrol_new_t snd_ac97_controls_si3036[] = { | ||
2470 | AC97_DOUBLE("Modem Speaker Volume", 0x5c, 14, 12, 3, 1) | ||
2471 | }; | ||
2472 | |||
2473 | static int patch_si3036_specific(ac97_t * ac97) | ||
2474 | { | ||
2475 | return patch_build_controls(ac97, snd_ac97_controls_si3036, ARRAY_SIZE(snd_ac97_controls_si3036)); | ||
2476 | } | ||
2477 | |||
2478 | static struct snd_ac97_build_ops patch_si3036_ops = { | ||
2479 | .build_specific = patch_si3036_specific, | ||
2480 | }; | ||
2302 | 2481 | ||
2303 | int mpatch_si3036(ac97_t * ac97) | 2482 | int mpatch_si3036(ac97_t * ac97) |
2304 | { | 2483 | { |
2305 | //printk("mpatch_si3036: chip id = %x\n", snd_ac97_read(ac97, 0x5a)); | 2484 | ac97->build_ops = &patch_si3036_ops; |
2306 | snd_ac97_write_cache(ac97, 0x5c, 0xf210 ); | 2485 | snd_ac97_write_cache(ac97, 0x5c, 0xf210 ); |
2307 | snd_ac97_write_cache(ac97, 0x68, 0); | 2486 | snd_ac97_write_cache(ac97, 0x68, 0); |
2308 | return 0; | 2487 | return 0; |