diff options
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 592 |
1 files changed, 494 insertions, 98 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c578c28f368e..194a28c54992 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -42,10 +42,12 @@ | |||
42 | 42 | ||
43 | /* Conexant 5051 specific */ | 43 | /* Conexant 5051 specific */ |
44 | 44 | ||
45 | #define CXT5051_SPDIF_OUT 0x1C | 45 | #define CXT5051_SPDIF_OUT 0x12 |
46 | #define CXT5051_PORTB_EVENT 0x38 | 46 | #define CXT5051_PORTB_EVENT 0x38 |
47 | #define CXT5051_PORTC_EVENT 0x39 | 47 | #define CXT5051_PORTC_EVENT 0x39 |
48 | 48 | ||
49 | #define AUTO_MIC_PORTB (1 << 1) | ||
50 | #define AUTO_MIC_PORTC (1 << 2) | ||
49 | 51 | ||
50 | struct conexant_jack { | 52 | struct conexant_jack { |
51 | 53 | ||
@@ -74,7 +76,7 @@ struct conexant_spec { | |||
74 | */ | 76 | */ |
75 | unsigned int cur_eapd; | 77 | unsigned int cur_eapd; |
76 | unsigned int hp_present; | 78 | unsigned int hp_present; |
77 | unsigned int no_auto_mic; | 79 | unsigned int auto_mic; |
78 | unsigned int need_dac_fix; | 80 | unsigned int need_dac_fix; |
79 | 81 | ||
80 | /* capture */ | 82 | /* capture */ |
@@ -111,8 +113,23 @@ struct conexant_spec { | |||
111 | 113 | ||
112 | unsigned int dell_automute; | 114 | unsigned int dell_automute; |
113 | unsigned int port_d_mode; | 115 | unsigned int port_d_mode; |
114 | unsigned char ext_mic_bias; | 116 | unsigned int dell_vostro:1; |
115 | unsigned int dell_vostro; | 117 | unsigned int ideapad:1; |
118 | |||
119 | unsigned int ext_mic_present; | ||
120 | unsigned int recording; | ||
121 | void (*capture_prepare)(struct hda_codec *codec); | ||
122 | void (*capture_cleanup)(struct hda_codec *codec); | ||
123 | |||
124 | /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) | ||
125 | * through the microphone jack. | ||
126 | * When the user enables this through a mixer switch, both internal and | ||
127 | * external microphones are disabled. Gain is fixed at 0dB. In this mode, | ||
128 | * we also allow the bias to be configured through a separate mixer | ||
129 | * control. */ | ||
130 | unsigned int dc_enable; | ||
131 | unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ | ||
132 | unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ | ||
116 | }; | 133 | }; |
117 | 134 | ||
118 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, | 135 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, |
@@ -185,6 +202,8 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
185 | struct snd_pcm_substream *substream) | 202 | struct snd_pcm_substream *substream) |
186 | { | 203 | { |
187 | struct conexant_spec *spec = codec->spec; | 204 | struct conexant_spec *spec = codec->spec; |
205 | if (spec->capture_prepare) | ||
206 | spec->capture_prepare(codec); | ||
188 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 207 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], |
189 | stream_tag, 0, format); | 208 | stream_tag, 0, format); |
190 | return 0; | 209 | return 0; |
@@ -196,6 +215,8 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
196 | { | 215 | { |
197 | struct conexant_spec *spec = codec->spec; | 216 | struct conexant_spec *spec = codec->spec; |
198 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); | 217 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); |
218 | if (spec->capture_cleanup) | ||
219 | spec->capture_cleanup(codec); | ||
199 | return 0; | 220 | return 0; |
200 | } | 221 | } |
201 | 222 | ||
@@ -1585,6 +1606,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec) | |||
1585 | { | 1606 | { |
1586 | struct conexant_spec *spec = codec->spec; | 1607 | struct conexant_spec *spec = codec->spec; |
1587 | unsigned int pinctl; | 1608 | unsigned int pinctl; |
1609 | /* headphone pin */ | ||
1610 | pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; | ||
1611 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1612 | pinctl); | ||
1613 | /* speaker pin */ | ||
1588 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | 1614 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; |
1589 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 1615 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, |
1590 | pinctl); | 1616 | pinctl); |
@@ -1608,7 +1634,7 @@ static void cxt5051_portb_automic(struct hda_codec *codec) | |||
1608 | struct conexant_spec *spec = codec->spec; | 1634 | struct conexant_spec *spec = codec->spec; |
1609 | unsigned int present; | 1635 | unsigned int present; |
1610 | 1636 | ||
1611 | if (spec->no_auto_mic) | 1637 | if (!(spec->auto_mic & AUTO_MIC_PORTB)) |
1612 | return; | 1638 | return; |
1613 | present = snd_hda_jack_detect(codec, 0x17); | 1639 | present = snd_hda_jack_detect(codec, 0x17); |
1614 | snd_hda_codec_write(codec, 0x14, 0, | 1640 | snd_hda_codec_write(codec, 0x14, 0, |
@@ -1623,7 +1649,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec) | |||
1623 | unsigned int present; | 1649 | unsigned int present; |
1624 | hda_nid_t new_adc; | 1650 | hda_nid_t new_adc; |
1625 | 1651 | ||
1626 | if (spec->no_auto_mic) | 1652 | if (!(spec->auto_mic & AUTO_MIC_PORTC)) |
1627 | return; | 1653 | return; |
1628 | present = snd_hda_jack_detect(codec, 0x18); | 1654 | present = snd_hda_jack_detect(codec, 0x18); |
1629 | if (present) | 1655 | if (present) |
@@ -1669,13 +1695,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, | |||
1669 | conexant_report_jack(codec, nid); | 1695 | conexant_report_jack(codec, nid); |
1670 | } | 1696 | } |
1671 | 1697 | ||
1672 | static struct snd_kcontrol_new cxt5051_mixers[] = { | 1698 | static struct snd_kcontrol_new cxt5051_playback_mixers[] = { |
1673 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1674 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1675 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
1676 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
1677 | HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), | ||
1678 | HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), | ||
1679 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | 1699 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), |
1680 | { | 1700 | { |
1681 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1701 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1685,7 +1705,16 @@ static struct snd_kcontrol_new cxt5051_mixers[] = { | |||
1685 | .put = cxt5051_hp_master_sw_put, | 1705 | .put = cxt5051_hp_master_sw_put, |
1686 | .private_value = 0x1a, | 1706 | .private_value = 0x1a, |
1687 | }, | 1707 | }, |
1708 | {} | ||
1709 | }; | ||
1688 | 1710 | ||
1711 | static struct snd_kcontrol_new cxt5051_capture_mixers[] = { | ||
1712 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1713 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1714 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
1715 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
1716 | HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), | ||
1717 | HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), | ||
1689 | {} | 1718 | {} |
1690 | }; | 1719 | }; |
1691 | 1720 | ||
@@ -1694,32 +1723,26 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = { | |||
1694 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | 1723 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), |
1695 | HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), | 1724 | HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), |
1696 | HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), | 1725 | HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), |
1697 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1698 | { | ||
1699 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1700 | .name = "Master Playback Switch", | ||
1701 | .info = cxt_eapd_info, | ||
1702 | .get = cxt_eapd_get, | ||
1703 | .put = cxt5051_hp_master_sw_put, | ||
1704 | .private_value = 0x1a, | ||
1705 | }, | ||
1706 | |||
1707 | {} | 1726 | {} |
1708 | }; | 1727 | }; |
1709 | 1728 | ||
1710 | static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { | 1729 | static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { |
1711 | HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x00, HDA_INPUT), | 1730 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), |
1712 | HDA_CODEC_MUTE("Mic Switch", 0x14, 0x00, HDA_INPUT), | 1731 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), |
1713 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | 1732 | {} |
1714 | { | 1733 | }; |
1715 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1716 | .name = "Master Playback Switch", | ||
1717 | .info = cxt_eapd_info, | ||
1718 | .get = cxt_eapd_get, | ||
1719 | .put = cxt5051_hp_master_sw_put, | ||
1720 | .private_value = 0x1a, | ||
1721 | }, | ||
1722 | 1734 | ||
1735 | static struct snd_kcontrol_new cxt5051_f700_mixers[] = { | ||
1736 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), | ||
1737 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), | ||
1738 | {} | ||
1739 | }; | ||
1740 | |||
1741 | static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { | ||
1742 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1743 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1744 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
1745 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
1723 | {} | 1746 | {} |
1724 | }; | 1747 | }; |
1725 | 1748 | ||
@@ -1748,8 +1771,6 @@ static struct hda_verb cxt5051_init_verbs[] = { | |||
1748 | /* EAPD */ | 1771 | /* EAPD */ |
1749 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 1772 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
1750 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | 1773 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, |
1751 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
1752 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, | ||
1753 | { } /* end */ | 1774 | { } /* end */ |
1754 | }; | 1775 | }; |
1755 | 1776 | ||
@@ -1775,7 +1796,6 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { | |||
1775 | /* EAPD */ | 1796 | /* EAPD */ |
1776 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 1797 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
1777 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | 1798 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, |
1778 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
1779 | { } /* end */ | 1799 | { } /* end */ |
1780 | }; | 1800 | }; |
1781 | 1801 | ||
@@ -1807,17 +1827,60 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | |||
1807 | /* EAPD */ | 1827 | /* EAPD */ |
1808 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 1828 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
1809 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | 1829 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, |
1810 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
1811 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, | ||
1812 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | 1830 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, |
1813 | { } /* end */ | 1831 | { } /* end */ |
1814 | }; | 1832 | }; |
1815 | 1833 | ||
1834 | static struct hda_verb cxt5051_f700_init_verbs[] = { | ||
1835 | /* Line in, Mic */ | ||
1836 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1837 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1838 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, | ||
1839 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, | ||
1840 | /* SPK */ | ||
1841 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1842 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1843 | /* HP, Amp */ | ||
1844 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1845 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1846 | /* DAC1 */ | ||
1847 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1848 | /* Record selector: Int mic */ | ||
1849 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | ||
1850 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1851 | /* SPDIF route: PCM */ | ||
1852 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1853 | /* EAPD */ | ||
1854 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
1855 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | ||
1856 | { } /* end */ | ||
1857 | }; | ||
1858 | |||
1859 | static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, | ||
1860 | unsigned int event) | ||
1861 | { | ||
1862 | snd_hda_codec_write(codec, nid, 0, | ||
1863 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1864 | AC_USRSP_EN | event); | ||
1865 | #ifdef CONFIG_SND_HDA_INPUT_JACK | ||
1866 | conexant_add_jack(codec, nid, SND_JACK_MICROPHONE); | ||
1867 | conexant_report_jack(codec, nid); | ||
1868 | #endif | ||
1869 | } | ||
1870 | |||
1816 | /* initialize jack-sensing, too */ | 1871 | /* initialize jack-sensing, too */ |
1817 | static int cxt5051_init(struct hda_codec *codec) | 1872 | static int cxt5051_init(struct hda_codec *codec) |
1818 | { | 1873 | { |
1874 | struct conexant_spec *spec = codec->spec; | ||
1875 | |||
1819 | conexant_init(codec); | 1876 | conexant_init(codec); |
1820 | conexant_init_jacks(codec); | 1877 | conexant_init_jacks(codec); |
1878 | |||
1879 | if (spec->auto_mic & AUTO_MIC_PORTB) | ||
1880 | cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); | ||
1881 | if (spec->auto_mic & AUTO_MIC_PORTC) | ||
1882 | cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT); | ||
1883 | |||
1821 | if (codec->patch_ops.unsol_event) { | 1884 | if (codec->patch_ops.unsol_event) { |
1822 | cxt5051_hp_automute(codec); | 1885 | cxt5051_hp_automute(codec); |
1823 | cxt5051_portb_automic(codec); | 1886 | cxt5051_portb_automic(codec); |
@@ -1832,6 +1895,8 @@ enum { | |||
1832 | CXT5051_HP, /* no docking */ | 1895 | CXT5051_HP, /* no docking */ |
1833 | CXT5051_HP_DV6736, /* HP without mic switch */ | 1896 | CXT5051_HP_DV6736, /* HP without mic switch */ |
1834 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ | 1897 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ |
1898 | CXT5051_F700, /* HP Compaq Presario F700 */ | ||
1899 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ | ||
1835 | CXT5051_MODELS | 1900 | CXT5051_MODELS |
1836 | }; | 1901 | }; |
1837 | 1902 | ||
@@ -1840,11 +1905,15 @@ static const char *cxt5051_models[CXT5051_MODELS] = { | |||
1840 | [CXT5051_HP] = "hp", | 1905 | [CXT5051_HP] = "hp", |
1841 | [CXT5051_HP_DV6736] = "hp-dv6736", | 1906 | [CXT5051_HP_DV6736] = "hp-dv6736", |
1842 | [CXT5051_LENOVO_X200] = "lenovo-x200", | 1907 | [CXT5051_LENOVO_X200] = "lenovo-x200", |
1908 | [CXT5051_F700] = "hp-700", | ||
1909 | [CXT5051_TOSHIBA] = "toshiba", | ||
1843 | }; | 1910 | }; |
1844 | 1911 | ||
1845 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1912 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { |
1846 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), | 1913 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), |
1847 | SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), | 1914 | SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), |
1915 | SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), | ||
1916 | SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA), | ||
1848 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", | 1917 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", |
1849 | CXT5051_LAPTOP), | 1918 | CXT5051_LAPTOP), |
1850 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | 1919 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), |
@@ -1872,8 +1941,9 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1872 | spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; | 1941 | spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; |
1873 | spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ | 1942 | spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ |
1874 | spec->adc_nids = cxt5051_adc_nids; | 1943 | spec->adc_nids = cxt5051_adc_nids; |
1875 | spec->num_mixers = 1; | 1944 | spec->num_mixers = 2; |
1876 | spec->mixers[0] = cxt5051_mixers; | 1945 | spec->mixers[0] = cxt5051_capture_mixers; |
1946 | spec->mixers[1] = cxt5051_playback_mixers; | ||
1877 | spec->num_init_verbs = 1; | 1947 | spec->num_init_verbs = 1; |
1878 | spec->init_verbs[0] = cxt5051_init_verbs; | 1948 | spec->init_verbs[0] = cxt5051_init_verbs; |
1879 | spec->spdif_route = 0; | 1949 | spec->spdif_route = 0; |
@@ -1887,6 +1957,7 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1887 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | 1957 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, |
1888 | cxt5051_models, | 1958 | cxt5051_models, |
1889 | cxt5051_cfg_tbl); | 1959 | cxt5051_cfg_tbl); |
1960 | spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; | ||
1890 | switch (board_config) { | 1961 | switch (board_config) { |
1891 | case CXT5051_HP: | 1962 | case CXT5051_HP: |
1892 | spec->mixers[0] = cxt5051_hp_mixers; | 1963 | spec->mixers[0] = cxt5051_hp_mixers; |
@@ -1894,11 +1965,20 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1894 | case CXT5051_HP_DV6736: | 1965 | case CXT5051_HP_DV6736: |
1895 | spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; | 1966 | spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; |
1896 | spec->mixers[0] = cxt5051_hp_dv6736_mixers; | 1967 | spec->mixers[0] = cxt5051_hp_dv6736_mixers; |
1897 | spec->no_auto_mic = 1; | 1968 | spec->auto_mic = 0; |
1898 | break; | 1969 | break; |
1899 | case CXT5051_LENOVO_X200: | 1970 | case CXT5051_LENOVO_X200: |
1900 | spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; | 1971 | spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; |
1901 | break; | 1972 | break; |
1973 | case CXT5051_F700: | ||
1974 | spec->init_verbs[0] = cxt5051_f700_init_verbs; | ||
1975 | spec->mixers[0] = cxt5051_f700_mixers; | ||
1976 | spec->auto_mic = 0; | ||
1977 | break; | ||
1978 | case CXT5051_TOSHIBA: | ||
1979 | spec->mixers[0] = cxt5051_toshiba_mixers; | ||
1980 | spec->auto_mic = AUTO_MIC_PORTB; | ||
1981 | break; | ||
1902 | } | 1982 | } |
1903 | 1983 | ||
1904 | return 0; | 1984 | return 0; |
@@ -1966,33 +2046,117 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
1966 | return 1; | 2046 | return 1; |
1967 | } | 2047 | } |
1968 | 2048 | ||
2049 | static const struct hda_input_mux cxt5066_olpc_dc_bias = { | ||
2050 | .num_items = 3, | ||
2051 | .items = { | ||
2052 | { "Off", PIN_IN }, | ||
2053 | { "50%", PIN_VREF50 }, | ||
2054 | { "80%", PIN_VREF80 }, | ||
2055 | }, | ||
2056 | }; | ||
2057 | |||
2058 | static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec) | ||
2059 | { | ||
2060 | struct conexant_spec *spec = codec->spec; | ||
2061 | /* Even though port F is the DC input, the bias is controlled on port B. | ||
2062 | * we also leave that port as an active input (but unselected) in DC mode | ||
2063 | * just in case that is necessary to make the bias setting take effect. */ | ||
2064 | return snd_hda_codec_write_cache(codec, 0x1a, 0, | ||
2065 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2066 | cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); | ||
2067 | } | ||
2068 | |||
2069 | /* OLPC defers mic widget control until when capture is started because the | ||
2070 | * microphone LED comes on as soon as these settings are put in place. if we | ||
2071 | * did this before recording, it would give the false indication that recording | ||
2072 | * is happening when it is not. */ | ||
2073 | static void cxt5066_olpc_select_mic(struct hda_codec *codec) | ||
2074 | { | ||
2075 | struct conexant_spec *spec = codec->spec; | ||
2076 | if (!spec->recording) | ||
2077 | return; | ||
2078 | |||
2079 | if (spec->dc_enable) { | ||
2080 | /* in DC mode we ignore presence detection and just use the jack | ||
2081 | * through our special DC port */ | ||
2082 | const struct hda_verb enable_dc_mode[] = { | ||
2083 | /* disble internal mic, port C */ | ||
2084 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2085 | |||
2086 | /* enable DC capture, port F */ | ||
2087 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2088 | {}, | ||
2089 | }; | ||
2090 | |||
2091 | snd_hda_sequence_write(codec, enable_dc_mode); | ||
2092 | /* port B input disabled (and bias set) through the following call */ | ||
2093 | cxt5066_set_olpc_dc_bias(codec); | ||
2094 | return; | ||
2095 | } | ||
2096 | |||
2097 | /* disable DC (port F) */ | ||
2098 | snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
2099 | |||
2100 | /* external mic, port B */ | ||
2101 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2102 | spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); | ||
2103 | |||
2104 | /* internal mic, port C */ | ||
2105 | snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2106 | spec->ext_mic_present ? 0 : PIN_VREF80); | ||
2107 | } | ||
2108 | |||
1969 | /* toggle input of built-in and mic jack appropriately */ | 2109 | /* toggle input of built-in and mic jack appropriately */ |
1970 | static void cxt5066_automic(struct hda_codec *codec) | 2110 | static void cxt5066_olpc_automic(struct hda_codec *codec) |
1971 | { | 2111 | { |
1972 | struct conexant_spec *spec = codec->spec; | 2112 | struct conexant_spec *spec = codec->spec; |
2113 | unsigned int present; | ||
2114 | |||
2115 | if (spec->dc_enable) /* don't do presence detection in DC mode */ | ||
2116 | return; | ||
2117 | |||
2118 | present = snd_hda_codec_read(codec, 0x1a, 0, | ||
2119 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
2120 | if (present) | ||
2121 | snd_printdd("CXT5066: external microphone detected\n"); | ||
2122 | else | ||
2123 | snd_printdd("CXT5066: external microphone absent\n"); | ||
2124 | |||
2125 | snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, | ||
2126 | present ? 0 : 1); | ||
2127 | spec->ext_mic_present = !!present; | ||
2128 | |||
2129 | cxt5066_olpc_select_mic(codec); | ||
2130 | } | ||
2131 | |||
2132 | /* toggle input of built-in digital mic and mic jack appropriately */ | ||
2133 | static void cxt5066_vostro_automic(struct hda_codec *codec) | ||
2134 | { | ||
2135 | unsigned int present; | ||
2136 | |||
1973 | struct hda_verb ext_mic_present[] = { | 2137 | struct hda_verb ext_mic_present[] = { |
1974 | /* enable external mic, port B */ | 2138 | /* enable external mic, port B */ |
1975 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, | 2139 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
1976 | 2140 | ||
1977 | /* switch to external mic input */ | 2141 | /* switch to external mic input */ |
1978 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | 2142 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, |
2143 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | ||
1979 | 2144 | ||
1980 | /* disable internal mic, port C */ | 2145 | /* disable internal digital mic */ |
1981 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2146 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
1982 | {} | 2147 | {} |
1983 | }; | 2148 | }; |
1984 | static struct hda_verb ext_mic_absent[] = { | 2149 | static struct hda_verb ext_mic_absent[] = { |
1985 | /* enable internal mic, port C */ | 2150 | /* enable internal mic, port C */ |
1986 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2151 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
1987 | 2152 | ||
1988 | /* switch to internal mic input */ | 2153 | /* switch to internal mic input */ |
1989 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, | 2154 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, |
1990 | 2155 | ||
1991 | /* disable external mic, port B */ | 2156 | /* disable external mic, port B */ |
1992 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2157 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
1993 | {} | 2158 | {} |
1994 | }; | 2159 | }; |
1995 | unsigned int present; | ||
1996 | 2160 | ||
1997 | present = snd_hda_jack_detect(codec, 0x1a); | 2161 | present = snd_hda_jack_detect(codec, 0x1a); |
1998 | if (present) { | 2162 | if (present) { |
@@ -2005,36 +2169,24 @@ static void cxt5066_automic(struct hda_codec *codec) | |||
2005 | } | 2169 | } |
2006 | 2170 | ||
2007 | /* toggle input of built-in digital mic and mic jack appropriately */ | 2171 | /* toggle input of built-in digital mic and mic jack appropriately */ |
2008 | static void cxt5066_vostro_automic(struct hda_codec *codec) | 2172 | static void cxt5066_ideapad_automic(struct hda_codec *codec) |
2009 | { | 2173 | { |
2010 | struct conexant_spec *spec = codec->spec; | ||
2011 | unsigned int present; | 2174 | unsigned int present; |
2012 | 2175 | ||
2013 | struct hda_verb ext_mic_present[] = { | 2176 | struct hda_verb ext_mic_present[] = { |
2014 | /* enable external mic, port B */ | ||
2015 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, | ||
2016 | |||
2017 | /* switch to external mic input */ | ||
2018 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | ||
2019 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | 2177 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, |
2020 | 2178 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | |
2021 | /* disable internal digital mic */ | ||
2022 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2179 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2023 | {} | 2180 | {} |
2024 | }; | 2181 | }; |
2025 | static struct hda_verb ext_mic_absent[] = { | 2182 | static struct hda_verb ext_mic_absent[] = { |
2026 | /* enable internal mic, port C */ | ||
2027 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2028 | |||
2029 | /* switch to internal mic input */ | ||
2030 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, | 2183 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, |
2031 | 2184 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | |
2032 | /* disable external mic, port B */ | 2185 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2033 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2034 | {} | 2186 | {} |
2035 | }; | 2187 | }; |
2036 | 2188 | ||
2037 | present = snd_hda_jack_detect(codec, 0x1a); | 2189 | present = snd_hda_jack_detect(codec, 0x1b); |
2038 | if (present) { | 2190 | if (present) { |
2039 | snd_printdd("CXT5066: external microphone detected\n"); | 2191 | snd_printdd("CXT5066: external microphone detected\n"); |
2040 | snd_hda_sequence_write(codec, ext_mic_present); | 2192 | snd_hda_sequence_write(codec, ext_mic_present); |
@@ -2063,15 +2215,18 @@ static void cxt5066_hp_automute(struct hda_codec *codec) | |||
2063 | } | 2215 | } |
2064 | 2216 | ||
2065 | /* unsolicited event for jack sensing */ | 2217 | /* unsolicited event for jack sensing */ |
2066 | static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) | 2218 | static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) |
2067 | { | 2219 | { |
2220 | struct conexant_spec *spec = codec->spec; | ||
2068 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); | 2221 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); |
2069 | switch (res >> 26) { | 2222 | switch (res >> 26) { |
2070 | case CONEXANT_HP_EVENT: | 2223 | case CONEXANT_HP_EVENT: |
2071 | cxt5066_hp_automute(codec); | 2224 | cxt5066_hp_automute(codec); |
2072 | break; | 2225 | break; |
2073 | case CONEXANT_MIC_EVENT: | 2226 | case CONEXANT_MIC_EVENT: |
2074 | cxt5066_automic(codec); | 2227 | /* ignore mic events in DC mode; we're always using the jack */ |
2228 | if (!spec->dc_enable) | ||
2229 | cxt5066_olpc_automic(codec); | ||
2075 | break; | 2230 | break; |
2076 | } | 2231 | } |
2077 | } | 2232 | } |
@@ -2090,6 +2245,20 @@ static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res) | |||
2090 | } | 2245 | } |
2091 | } | 2246 | } |
2092 | 2247 | ||
2248 | /* unsolicited event for jack sensing */ | ||
2249 | static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) | ||
2250 | { | ||
2251 | snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26); | ||
2252 | switch (res >> 26) { | ||
2253 | case CONEXANT_HP_EVENT: | ||
2254 | cxt5066_hp_automute(codec); | ||
2255 | break; | ||
2256 | case CONEXANT_MIC_EVENT: | ||
2257 | cxt5066_ideapad_automic(codec); | ||
2258 | break; | ||
2259 | } | ||
2260 | } | ||
2261 | |||
2093 | static const struct hda_input_mux cxt5066_analog_mic_boost = { | 2262 | static const struct hda_input_mux cxt5066_analog_mic_boost = { |
2094 | .num_items = 5, | 2263 | .num_items = 5, |
2095 | .items = { | 2264 | .items = { |
@@ -2101,6 +2270,23 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = { | |||
2101 | }, | 2270 | }, |
2102 | }; | 2271 | }; |
2103 | 2272 | ||
2273 | static void cxt5066_set_mic_boost(struct hda_codec *codec) | ||
2274 | { | ||
2275 | struct conexant_spec *spec = codec->spec; | ||
2276 | snd_hda_codec_write_cache(codec, 0x17, 0, | ||
2277 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2278 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | | ||
2279 | cxt5066_analog_mic_boost.items[spec->mic_boost].index); | ||
2280 | if (spec->ideapad) { | ||
2281 | /* adjust the internal mic as well...it is not through 0x17 */ | ||
2282 | snd_hda_codec_write_cache(codec, 0x23, 0, | ||
2283 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2284 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT | | ||
2285 | cxt5066_analog_mic_boost. | ||
2286 | items[spec->mic_boost].index); | ||
2287 | } | ||
2288 | } | ||
2289 | |||
2104 | static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, | 2290 | static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, |
2105 | struct snd_ctl_elem_info *uinfo) | 2291 | struct snd_ctl_elem_info *uinfo) |
2106 | { | 2292 | { |
@@ -2111,15 +2297,8 @@ static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, | |||
2111 | struct snd_ctl_elem_value *ucontrol) | 2297 | struct snd_ctl_elem_value *ucontrol) |
2112 | { | 2298 | { |
2113 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2299 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2114 | int val; | 2300 | struct conexant_spec *spec = codec->spec; |
2115 | hda_nid_t nid = kcontrol->private_value & 0xff; | 2301 | ucontrol->value.enumerated.item[0] = spec->mic_boost; |
2116 | int inout = (kcontrol->private_value & 0x100) ? | ||
2117 | AC_AMP_GET_INPUT : AC_AMP_GET_OUTPUT; | ||
2118 | |||
2119 | val = snd_hda_codec_read(codec, nid, 0, | ||
2120 | AC_VERB_GET_AMP_GAIN_MUTE, inout); | ||
2121 | |||
2122 | ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN; | ||
2123 | return 0; | 2302 | return 0; |
2124 | } | 2303 | } |
2125 | 2304 | ||
@@ -2127,26 +2306,132 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
2127 | struct snd_ctl_elem_value *ucontrol) | 2306 | struct snd_ctl_elem_value *ucontrol) |
2128 | { | 2307 | { |
2129 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2308 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2309 | struct conexant_spec *spec = codec->spec; | ||
2130 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; | 2310 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; |
2131 | unsigned int idx; | 2311 | unsigned int idx; |
2132 | hda_nid_t nid = kcontrol->private_value & 0xff; | 2312 | idx = ucontrol->value.enumerated.item[0]; |
2133 | int inout = (kcontrol->private_value & 0x100) ? | 2313 | if (idx >= imux->num_items) |
2134 | AC_AMP_SET_INPUT : AC_AMP_SET_OUTPUT; | 2314 | idx = imux->num_items - 1; |
2315 | |||
2316 | spec->mic_boost = idx; | ||
2317 | if (!spec->dc_enable) | ||
2318 | cxt5066_set_mic_boost(codec); | ||
2319 | return 1; | ||
2320 | } | ||
2321 | |||
2322 | static void cxt5066_enable_dc(struct hda_codec *codec) | ||
2323 | { | ||
2324 | const struct hda_verb enable_dc_mode[] = { | ||
2325 | /* disable gain */ | ||
2326 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2327 | |||
2328 | /* switch to DC input */ | ||
2329 | {0x17, AC_VERB_SET_CONNECT_SEL, 3}, | ||
2330 | {} | ||
2331 | }; | ||
2332 | |||
2333 | /* configure as input source */ | ||
2334 | snd_hda_sequence_write(codec, enable_dc_mode); | ||
2335 | cxt5066_olpc_select_mic(codec); /* also sets configured bias */ | ||
2336 | } | ||
2337 | |||
2338 | static void cxt5066_disable_dc(struct hda_codec *codec) | ||
2339 | { | ||
2340 | /* reconfigure input source */ | ||
2341 | cxt5066_set_mic_boost(codec); | ||
2342 | /* automic also selects the right mic if we're recording */ | ||
2343 | cxt5066_olpc_automic(codec); | ||
2344 | } | ||
2345 | |||
2346 | static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol, | ||
2347 | struct snd_ctl_elem_value *ucontrol) | ||
2348 | { | ||
2349 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2350 | struct conexant_spec *spec = codec->spec; | ||
2351 | ucontrol->value.integer.value[0] = spec->dc_enable; | ||
2352 | return 0; | ||
2353 | } | ||
2135 | 2354 | ||
2136 | if (!imux->num_items) | 2355 | static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol, |
2356 | struct snd_ctl_elem_value *ucontrol) | ||
2357 | { | ||
2358 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2359 | struct conexant_spec *spec = codec->spec; | ||
2360 | int dc_enable = !!ucontrol->value.integer.value[0]; | ||
2361 | |||
2362 | if (dc_enable == spec->dc_enable) | ||
2137 | return 0; | 2363 | return 0; |
2364 | |||
2365 | spec->dc_enable = dc_enable; | ||
2366 | if (dc_enable) | ||
2367 | cxt5066_enable_dc(codec); | ||
2368 | else | ||
2369 | cxt5066_disable_dc(codec); | ||
2370 | |||
2371 | return 1; | ||
2372 | } | ||
2373 | |||
2374 | static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol, | ||
2375 | struct snd_ctl_elem_info *uinfo) | ||
2376 | { | ||
2377 | return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo); | ||
2378 | } | ||
2379 | |||
2380 | static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol, | ||
2381 | struct snd_ctl_elem_value *ucontrol) | ||
2382 | { | ||
2383 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2384 | struct conexant_spec *spec = codec->spec; | ||
2385 | ucontrol->value.enumerated.item[0] = spec->dc_input_bias; | ||
2386 | return 0; | ||
2387 | } | ||
2388 | |||
2389 | static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol, | ||
2390 | struct snd_ctl_elem_value *ucontrol) | ||
2391 | { | ||
2392 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2393 | struct conexant_spec *spec = codec->spec; | ||
2394 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; | ||
2395 | unsigned int idx; | ||
2396 | |||
2138 | idx = ucontrol->value.enumerated.item[0]; | 2397 | idx = ucontrol->value.enumerated.item[0]; |
2139 | if (idx >= imux->num_items) | 2398 | if (idx >= imux->num_items) |
2140 | idx = imux->num_items - 1; | 2399 | idx = imux->num_items - 1; |
2141 | 2400 | ||
2142 | snd_hda_codec_write_cache(codec, nid, 0, | 2401 | spec->dc_input_bias = idx; |
2143 | AC_VERB_SET_AMP_GAIN_MUTE, | 2402 | if (spec->dc_enable) |
2144 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | inout | | 2403 | cxt5066_set_olpc_dc_bias(codec); |
2145 | imux->items[idx].index); | ||
2146 | |||
2147 | return 1; | 2404 | return 1; |
2148 | } | 2405 | } |
2149 | 2406 | ||
2407 | static void cxt5066_olpc_capture_prepare(struct hda_codec *codec) | ||
2408 | { | ||
2409 | struct conexant_spec *spec = codec->spec; | ||
2410 | /* mark as recording and configure the microphone widget so that the | ||
2411 | * recording LED comes on. */ | ||
2412 | spec->recording = 1; | ||
2413 | cxt5066_olpc_select_mic(codec); | ||
2414 | } | ||
2415 | |||
2416 | static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) | ||
2417 | { | ||
2418 | struct conexant_spec *spec = codec->spec; | ||
2419 | const struct hda_verb disable_mics[] = { | ||
2420 | /* disable external mic, port B */ | ||
2421 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2422 | |||
2423 | /* disble internal mic, port C */ | ||
2424 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2425 | |||
2426 | /* disable DC capture, port F */ | ||
2427 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2428 | {}, | ||
2429 | }; | ||
2430 | |||
2431 | snd_hda_sequence_write(codec, disable_mics); | ||
2432 | spec->recording = 0; | ||
2433 | } | ||
2434 | |||
2150 | static struct hda_input_mux cxt5066_capture_source = { | 2435 | static struct hda_input_mux cxt5066_capture_source = { |
2151 | .num_items = 4, | 2436 | .num_items = 4, |
2152 | .items = { | 2437 | .items = { |
@@ -2187,6 +2472,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | |||
2187 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 2472 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
2188 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 2473 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
2189 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, | 2474 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, |
2475 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
2190 | .info = snd_hda_mixer_amp_volume_info, | 2476 | .info = snd_hda_mixer_amp_volume_info, |
2191 | .get = snd_hda_mixer_amp_volume_get, | 2477 | .get = snd_hda_mixer_amp_volume_get, |
2192 | .put = snd_hda_mixer_amp_volume_put, | 2478 | .put = snd_hda_mixer_amp_volume_put, |
@@ -2198,6 +2484,24 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | |||
2198 | {} | 2484 | {} |
2199 | }; | 2485 | }; |
2200 | 2486 | ||
2487 | static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { | ||
2488 | { | ||
2489 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2490 | .name = "DC Mode Enable Switch", | ||
2491 | .info = snd_ctl_boolean_mono_info, | ||
2492 | .get = cxt5066_olpc_dc_get, | ||
2493 | .put = cxt5066_olpc_dc_put, | ||
2494 | }, | ||
2495 | { | ||
2496 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2497 | .name = "DC Input Bias Enum", | ||
2498 | .info = cxt5066_olpc_dc_bias_enum_info, | ||
2499 | .get = cxt5066_olpc_dc_bias_enum_get, | ||
2500 | .put = cxt5066_olpc_dc_bias_enum_put, | ||
2501 | }, | ||
2502 | {} | ||
2503 | }; | ||
2504 | |||
2201 | static struct snd_kcontrol_new cxt5066_mixers[] = { | 2505 | static struct snd_kcontrol_new cxt5066_mixers[] = { |
2202 | { | 2506 | { |
2203 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2507 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -2210,11 +2514,10 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { | |||
2210 | 2514 | ||
2211 | { | 2515 | { |
2212 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2516 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2213 | .name = "Ext Mic Boost Capture Enum", | 2517 | .name = "Analog Mic Boost Capture Enum", |
2214 | .info = cxt5066_mic_boost_mux_enum_info, | 2518 | .info = cxt5066_mic_boost_mux_enum_info, |
2215 | .get = cxt5066_mic_boost_mux_enum_get, | 2519 | .get = cxt5066_mic_boost_mux_enum_get, |
2216 | .put = cxt5066_mic_boost_mux_enum_put, | 2520 | .put = cxt5066_mic_boost_mux_enum_put, |
2217 | .private_value = 0x17, | ||
2218 | }, | 2521 | }, |
2219 | 2522 | ||
2220 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), | 2523 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), |
@@ -2296,10 +2599,10 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2296 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | 2599 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ |
2297 | 2600 | ||
2298 | /* Port B: external microphone */ | 2601 | /* Port B: external microphone */ |
2299 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, | 2602 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2300 | 2603 | ||
2301 | /* Port C: internal microphone */ | 2604 | /* Port C: internal microphone */ |
2302 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2605 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2303 | 2606 | ||
2304 | /* Port D: unused */ | 2607 | /* Port D: unused */ |
2305 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2608 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
@@ -2308,7 +2611,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2308 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2611 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2309 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 2612 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
2310 | 2613 | ||
2311 | /* Port F: unused */ | 2614 | /* Port F: external DC input through microphone port */ |
2312 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2615 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2313 | 2616 | ||
2314 | /* Port G: internal speakers */ | 2617 | /* Port G: internal speakers */ |
@@ -2412,6 +2715,56 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = { | |||
2412 | { } /* end */ | 2715 | { } /* end */ |
2413 | }; | 2716 | }; |
2414 | 2717 | ||
2718 | static struct hda_verb cxt5066_init_verbs_ideapad[] = { | ||
2719 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ | ||
2720 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ | ||
2721 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ | ||
2722 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ | ||
2723 | |||
2724 | /* Speakers */ | ||
2725 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2726 | {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2727 | |||
2728 | /* HP, Amp */ | ||
2729 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2730 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2731 | |||
2732 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2733 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2734 | |||
2735 | /* DAC1 */ | ||
2736 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2737 | |||
2738 | /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ | ||
2739 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, | ||
2740 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2741 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, | ||
2742 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2743 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2744 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ | ||
2745 | |||
2746 | /* Audio input selector */ | ||
2747 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, | ||
2748 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ | ||
2749 | |||
2750 | /* SPDIF route: PCM */ | ||
2751 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2752 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2753 | |||
2754 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2755 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2756 | |||
2757 | /* internal microphone */ | ||
2758 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ | ||
2759 | |||
2760 | /* EAPD */ | ||
2761 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
2762 | |||
2763 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||
2764 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | ||
2765 | { } /* end */ | ||
2766 | }; | ||
2767 | |||
2415 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { | 2768 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { |
2416 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 2769 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
2417 | { } /* end */ | 2770 | { } /* end */ |
@@ -2428,8 +2781,24 @@ static int cxt5066_init(struct hda_codec *codec) | |||
2428 | cxt5066_hp_automute(codec); | 2781 | cxt5066_hp_automute(codec); |
2429 | if (spec->dell_vostro) | 2782 | if (spec->dell_vostro) |
2430 | cxt5066_vostro_automic(codec); | 2783 | cxt5066_vostro_automic(codec); |
2431 | else | 2784 | else if (spec->ideapad) |
2432 | cxt5066_automic(codec); | 2785 | cxt5066_ideapad_automic(codec); |
2786 | } | ||
2787 | cxt5066_set_mic_boost(codec); | ||
2788 | return 0; | ||
2789 | } | ||
2790 | |||
2791 | static int cxt5066_olpc_init(struct hda_codec *codec) | ||
2792 | { | ||
2793 | struct conexant_spec *spec = codec->spec; | ||
2794 | snd_printdd("CXT5066: init\n"); | ||
2795 | conexant_init(codec); | ||
2796 | cxt5066_hp_automute(codec); | ||
2797 | if (!spec->dc_enable) { | ||
2798 | cxt5066_set_mic_boost(codec); | ||
2799 | cxt5066_olpc_automic(codec); | ||
2800 | } else { | ||
2801 | cxt5066_enable_dc(codec); | ||
2433 | } | 2802 | } |
2434 | return 0; | 2803 | return 0; |
2435 | } | 2804 | } |
@@ -2439,6 +2808,7 @@ enum { | |||
2439 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ | 2808 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ |
2440 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ | 2809 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ |
2441 | CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ | 2810 | CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ |
2811 | CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ | ||
2442 | CXT5066_MODELS | 2812 | CXT5066_MODELS |
2443 | }; | 2813 | }; |
2444 | 2814 | ||
@@ -2446,7 +2816,8 @@ static const char *cxt5066_models[CXT5066_MODELS] = { | |||
2446 | [CXT5066_LAPTOP] = "laptop", | 2816 | [CXT5066_LAPTOP] = "laptop", |
2447 | [CXT5066_DELL_LAPTOP] = "dell-laptop", | 2817 | [CXT5066_DELL_LAPTOP] = "dell-laptop", |
2448 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", | 2818 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", |
2449 | [CXT5066_DELL_VOSTO] = "dell-vostro" | 2819 | [CXT5066_DELL_VOSTO] = "dell-vostro", |
2820 | [CXT5066_IDEAPAD] = "ideapad", | ||
2450 | }; | 2821 | }; |
2451 | 2822 | ||
2452 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | 2823 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { |
@@ -2456,6 +2827,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | |||
2456 | CXT5066_DELL_LAPTOP), | 2827 | CXT5066_DELL_LAPTOP), |
2457 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), | 2828 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), |
2458 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), | 2829 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), |
2830 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), | ||
2459 | {} | 2831 | {} |
2460 | }; | 2832 | }; |
2461 | 2833 | ||
@@ -2470,7 +2842,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2470 | codec->spec = spec; | 2842 | codec->spec = spec; |
2471 | 2843 | ||
2472 | codec->patch_ops = conexant_patch_ops; | 2844 | codec->patch_ops = conexant_patch_ops; |
2473 | codec->patch_ops.init = cxt5066_init; | 2845 | codec->patch_ops.init = conexant_init; |
2474 | 2846 | ||
2475 | spec->dell_automute = 0; | 2847 | spec->dell_automute = 0; |
2476 | spec->multiout.max_channels = 2; | 2848 | spec->multiout.max_channels = 2; |
@@ -2483,7 +2855,6 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2483 | spec->input_mux = &cxt5066_capture_source; | 2855 | spec->input_mux = &cxt5066_capture_source; |
2484 | 2856 | ||
2485 | spec->port_d_mode = PIN_HP; | 2857 | spec->port_d_mode = PIN_HP; |
2486 | spec->ext_mic_bias = PIN_VREF80; | ||
2487 | 2858 | ||
2488 | spec->num_init_verbs = 1; | 2859 | spec->num_init_verbs = 1; |
2489 | spec->init_verbs[0] = cxt5066_init_verbs; | 2860 | spec->init_verbs[0] = cxt5066_init_verbs; |
@@ -2510,20 +2881,28 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2510 | spec->dell_automute = 1; | 2881 | spec->dell_automute = 1; |
2511 | break; | 2882 | break; |
2512 | case CXT5066_OLPC_XO_1_5: | 2883 | case CXT5066_OLPC_XO_1_5: |
2513 | codec->patch_ops.unsol_event = cxt5066_unsol_event; | 2884 | codec->patch_ops.init = cxt5066_olpc_init; |
2885 | codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; | ||
2514 | spec->init_verbs[0] = cxt5066_init_verbs_olpc; | 2886 | spec->init_verbs[0] = cxt5066_init_verbs_olpc; |
2515 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 2887 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
2888 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc; | ||
2516 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 2889 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
2517 | spec->port_d_mode = 0; | 2890 | spec->port_d_mode = 0; |
2518 | spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS; | 2891 | spec->mic_boost = 3; /* default 30dB gain */ |
2519 | 2892 | ||
2520 | /* no S/PDIF out */ | 2893 | /* no S/PDIF out */ |
2521 | spec->multiout.dig_out_nid = 0; | 2894 | spec->multiout.dig_out_nid = 0; |
2522 | 2895 | ||
2523 | /* input source automatically selected */ | 2896 | /* input source automatically selected */ |
2524 | spec->input_mux = NULL; | 2897 | spec->input_mux = NULL; |
2898 | |||
2899 | /* our capture hooks which allow us to turn on the microphone LED | ||
2900 | * at the right time */ | ||
2901 | spec->capture_prepare = cxt5066_olpc_capture_prepare; | ||
2902 | spec->capture_cleanup = cxt5066_olpc_capture_cleanup; | ||
2525 | break; | 2903 | break; |
2526 | case CXT5066_DELL_VOSTO: | 2904 | case CXT5066_DELL_VOSTO: |
2905 | codec->patch_ops.init = cxt5066_init; | ||
2527 | codec->patch_ops.unsol_event = cxt5066_vostro_event; | 2906 | codec->patch_ops.unsol_event = cxt5066_vostro_event; |
2528 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; | 2907 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; |
2529 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 2908 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
@@ -2531,6 +2910,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2531 | spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; | 2910 | spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; |
2532 | spec->port_d_mode = 0; | 2911 | spec->port_d_mode = 0; |
2533 | spec->dell_vostro = 1; | 2912 | spec->dell_vostro = 1; |
2913 | spec->mic_boost = 3; /* default 30dB gain */ | ||
2534 | snd_hda_attach_beep_device(codec, 0x13); | 2914 | snd_hda_attach_beep_device(codec, 0x13); |
2535 | 2915 | ||
2536 | /* no S/PDIF out */ | 2916 | /* no S/PDIF out */ |
@@ -2539,6 +2919,22 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2539 | /* input source automatically selected */ | 2919 | /* input source automatically selected */ |
2540 | spec->input_mux = NULL; | 2920 | spec->input_mux = NULL; |
2541 | break; | 2921 | break; |
2922 | case CXT5066_IDEAPAD: | ||
2923 | codec->patch_ops.init = cxt5066_init; | ||
2924 | codec->patch_ops.unsol_event = cxt5066_ideapad_event; | ||
2925 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | ||
2926 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | ||
2927 | spec->init_verbs[0] = cxt5066_init_verbs_ideapad; | ||
2928 | spec->port_d_mode = 0; | ||
2929 | spec->ideapad = 1; | ||
2930 | spec->mic_boost = 2; /* default 20dB gain */ | ||
2931 | |||
2932 | /* no S/PDIF out */ | ||
2933 | spec->multiout.dig_out_nid = 0; | ||
2934 | |||
2935 | /* input source automatically selected */ | ||
2936 | spec->input_mux = NULL; | ||
2937 | break; | ||
2542 | } | 2938 | } |
2543 | 2939 | ||
2544 | return 0; | 2940 | return 0; |