aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_conexant.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r--sound/pci/hda/patch_conexant.c592
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
50struct conexant_jack { 52struct 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
118static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, 135static 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
1672static struct snd_kcontrol_new cxt5051_mixers[] = { 1698static 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
1711static 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
1710static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { 1729static 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
1735static 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
1741static 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
1834static 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
1859static 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 */
1817static int cxt5051_init(struct hda_codec *codec) 1872static 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
1845static struct snd_pci_quirk cxt5051_cfg_tbl[] = { 1912static 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
2049static 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
2058static 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. */
2073static 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 */
1970static void cxt5066_automic(struct hda_codec *codec) 2110static 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 */
2133static 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 */
2008static void cxt5066_vostro_automic(struct hda_codec *codec) 2172static 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 */
2066static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) 2218static 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 */
2249static 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
2093static const struct hda_input_mux cxt5066_analog_mic_boost = { 2262static 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
2273static 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
2104static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, 2290static 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
2322static 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
2338static 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
2346static 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) 2355static 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
2374static 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
2380static 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
2389static 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
2407static 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
2416static 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
2150static struct hda_input_mux cxt5066_capture_source = { 2435static 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
2487static 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
2201static struct snd_kcontrol_new cxt5066_mixers[] = { 2505static 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
2718static 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
2415static struct hda_verb cxt5066_init_verbs_portd_lo[] = { 2768static 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
2791static 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
2452static struct snd_pci_quirk cxt5066_cfg_tbl[] = { 2823static 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;