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.c255
1 files changed, 194 insertions, 61 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 685015a53292..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,7 +113,8 @@ 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 int dell_vostro; 116 unsigned int dell_vostro:1;
117 unsigned int ideapad:1;
115 118
116 unsigned int ext_mic_present; 119 unsigned int ext_mic_present;
117 unsigned int recording; 120 unsigned int recording;
@@ -1603,6 +1606,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec)
1603{ 1606{
1604 struct conexant_spec *spec = codec->spec; 1607 struct conexant_spec *spec = codec->spec;
1605 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 */
1606 pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; 1614 pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
1607 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,
1608 pinctl); 1616 pinctl);
@@ -1626,7 +1634,7 @@ static void cxt5051_portb_automic(struct hda_codec *codec)
1626 struct conexant_spec *spec = codec->spec; 1634 struct conexant_spec *spec = codec->spec;
1627 unsigned int present; 1635 unsigned int present;
1628 1636
1629 if (spec->no_auto_mic) 1637 if (!(spec->auto_mic & AUTO_MIC_PORTB))
1630 return; 1638 return;
1631 present = snd_hda_jack_detect(codec, 0x17); 1639 present = snd_hda_jack_detect(codec, 0x17);
1632 snd_hda_codec_write(codec, 0x14, 0, 1640 snd_hda_codec_write(codec, 0x14, 0,
@@ -1641,7 +1649,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec)
1641 unsigned int present; 1649 unsigned int present;
1642 hda_nid_t new_adc; 1650 hda_nid_t new_adc;
1643 1651
1644 if (spec->no_auto_mic) 1652 if (!(spec->auto_mic & AUTO_MIC_PORTC))
1645 return; 1653 return;
1646 present = snd_hda_jack_detect(codec, 0x18); 1654 present = snd_hda_jack_detect(codec, 0x18);
1647 if (present) 1655 if (present)
@@ -1687,13 +1695,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
1687 conexant_report_jack(codec, nid); 1695 conexant_report_jack(codec, nid);
1688} 1696}
1689 1697
1690static struct snd_kcontrol_new cxt5051_mixers[] = { 1698static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
1691 HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
1692 HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
1693 HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
1694 HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
1695 HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
1696 HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
1697 HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), 1699 HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
1698 { 1700 {
1699 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1701 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1703,7 +1705,16 @@ static struct snd_kcontrol_new cxt5051_mixers[] = {
1703 .put = cxt5051_hp_master_sw_put, 1705 .put = cxt5051_hp_master_sw_put,
1704 .private_value = 0x1a, 1706 .private_value = 0x1a,
1705 }, 1707 },
1708 {}
1709};
1706 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),
1707 {} 1718 {}
1708}; 1719};
1709 1720
@@ -1712,48 +1723,26 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
1712 HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), 1723 HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
1713 HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), 1724 HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT),
1714 HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), 1725 HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT),
1715 HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
1716 {
1717 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1718 .name = "Master Playback Switch",
1719 .info = cxt_eapd_info,
1720 .get = cxt_eapd_get,
1721 .put = cxt5051_hp_master_sw_put,
1722 .private_value = 0x1a,
1723 },
1724
1725 {} 1726 {}
1726}; 1727};
1727 1728
1728static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { 1729static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
1729 HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x00, HDA_INPUT), 1730 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT),
1730 HDA_CODEC_MUTE("Mic Switch", 0x14, 0x00, HDA_INPUT), 1731 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT),
1731 HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
1732 {
1733 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1734 .name = "Master Playback Switch",
1735 .info = cxt_eapd_info,
1736 .get = cxt_eapd_get,
1737 .put = cxt5051_hp_master_sw_put,
1738 .private_value = 0x1a,
1739 },
1740
1741 {} 1732 {}
1742}; 1733};
1743 1734
1744static struct snd_kcontrol_new cxt5051_f700_mixers[] = { 1735static struct snd_kcontrol_new cxt5051_f700_mixers[] = {
1745 HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), 1736 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT),
1746 HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), 1737 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT),
1747 HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), 1738 {}
1748 { 1739};
1749 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1750 .name = "Master Playback Switch",
1751 .info = cxt_eapd_info,
1752 .get = cxt_eapd_get,
1753 .put = cxt5051_hp_master_sw_put,
1754 .private_value = 0x1a,
1755 },
1756 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),
1757 {} 1746 {}
1758}; 1747};
1759 1748
@@ -1782,8 +1771,6 @@ static struct hda_verb cxt5051_init_verbs[] = {
1782 /* EAPD */ 1771 /* EAPD */
1783 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 1772 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
1784 {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},
1785 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
1786 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
1787 { } /* end */ 1774 { } /* end */
1788}; 1775};
1789 1776
@@ -1809,7 +1796,6 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
1809 /* EAPD */ 1796 /* EAPD */
1810 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 1797 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
1811 {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},
1812 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
1813 { } /* end */ 1799 { } /* end */
1814}; 1800};
1815 1801
@@ -1841,15 +1827,13 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
1841 /* EAPD */ 1827 /* EAPD */
1842 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 1828 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
1843 {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},
1844 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
1845 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
1846 {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},
1847 { } /* end */ 1831 { } /* end */
1848}; 1832};
1849 1833
1850static struct hda_verb cxt5051_f700_init_verbs[] = { 1834static struct hda_verb cxt5051_f700_init_verbs[] = {
1851 /* Line in, Mic */ 1835 /* Line in, Mic */
1852 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x03}, 1836 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1853 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1837 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1854 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, 1838 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
1855 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, 1839 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
@@ -1869,15 +1853,34 @@ static struct hda_verb cxt5051_f700_init_verbs[] = {
1869 /* EAPD */ 1853 /* EAPD */
1870 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 1854 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
1871 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, 1855 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
1872 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
1873 { } /* end */ 1856 { } /* end */
1874}; 1857};
1875 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
1876/* initialize jack-sensing, too */ 1871/* initialize jack-sensing, too */
1877static int cxt5051_init(struct hda_codec *codec) 1872static int cxt5051_init(struct hda_codec *codec)
1878{ 1873{
1874 struct conexant_spec *spec = codec->spec;
1875
1879 conexant_init(codec); 1876 conexant_init(codec);
1880 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
1881 if (codec->patch_ops.unsol_event) { 1884 if (codec->patch_ops.unsol_event) {
1882 cxt5051_hp_automute(codec); 1885 cxt5051_hp_automute(codec);
1883 cxt5051_portb_automic(codec); 1886 cxt5051_portb_automic(codec);
@@ -1893,6 +1896,7 @@ enum {
1893 CXT5051_HP_DV6736, /* HP without mic switch */ 1896 CXT5051_HP_DV6736, /* HP without mic switch */
1894 CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ 1897 CXT5051_LENOVO_X200, /* Lenovo X200 laptop */
1895 CXT5051_F700, /* HP Compaq Presario F700 */ 1898 CXT5051_F700, /* HP Compaq Presario F700 */
1899 CXT5051_TOSHIBA, /* Toshiba M300 & co */
1896 CXT5051_MODELS 1900 CXT5051_MODELS
1897}; 1901};
1898 1902
@@ -1901,17 +1905,19 @@ static const char *cxt5051_models[CXT5051_MODELS] = {
1901 [CXT5051_HP] = "hp", 1905 [CXT5051_HP] = "hp",
1902 [CXT5051_HP_DV6736] = "hp-dv6736", 1906 [CXT5051_HP_DV6736] = "hp-dv6736",
1903 [CXT5051_LENOVO_X200] = "lenovo-x200", 1907 [CXT5051_LENOVO_X200] = "lenovo-x200",
1904 [CXT5051_F700] = "hp 700" 1908 [CXT5051_F700] = "hp-700",
1909 [CXT5051_TOSHIBA] = "toshiba",
1905}; 1910};
1906 1911
1907static struct snd_pci_quirk cxt5051_cfg_tbl[] = { 1912static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
1908 SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), 1913 SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736),
1909 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),
1910 SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", 1917 SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
1911 CXT5051_LAPTOP), 1918 CXT5051_LAPTOP),
1912 SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), 1919 SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
1913 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), 1920 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
1914 SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700),
1915 {} 1921 {}
1916}; 1922};
1917 1923
@@ -1935,8 +1941,9 @@ static int patch_cxt5051(struct hda_codec *codec)
1935 spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; 1941 spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT;
1936 spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ 1942 spec->num_adc_nids = 1; /* not 2; via auto-mic switch */
1937 spec->adc_nids = cxt5051_adc_nids; 1943 spec->adc_nids = cxt5051_adc_nids;
1938 spec->num_mixers = 1; 1944 spec->num_mixers = 2;
1939 spec->mixers[0] = cxt5051_mixers; 1945 spec->mixers[0] = cxt5051_capture_mixers;
1946 spec->mixers[1] = cxt5051_playback_mixers;
1940 spec->num_init_verbs = 1; 1947 spec->num_init_verbs = 1;
1941 spec->init_verbs[0] = cxt5051_init_verbs; 1948 spec->init_verbs[0] = cxt5051_init_verbs;
1942 spec->spdif_route = 0; 1949 spec->spdif_route = 0;
@@ -1950,6 +1957,7 @@ static int patch_cxt5051(struct hda_codec *codec)
1950 board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, 1957 board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
1951 cxt5051_models, 1958 cxt5051_models,
1952 cxt5051_cfg_tbl); 1959 cxt5051_cfg_tbl);
1960 spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC;
1953 switch (board_config) { 1961 switch (board_config) {
1954 case CXT5051_HP: 1962 case CXT5051_HP:
1955 spec->mixers[0] = cxt5051_hp_mixers; 1963 spec->mixers[0] = cxt5051_hp_mixers;
@@ -1957,7 +1965,7 @@ static int patch_cxt5051(struct hda_codec *codec)
1957 case CXT5051_HP_DV6736: 1965 case CXT5051_HP_DV6736:
1958 spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; 1966 spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs;
1959 spec->mixers[0] = cxt5051_hp_dv6736_mixers; 1967 spec->mixers[0] = cxt5051_hp_dv6736_mixers;
1960 spec->no_auto_mic = 1; 1968 spec->auto_mic = 0;
1961 break; 1969 break;
1962 case CXT5051_LENOVO_X200: 1970 case CXT5051_LENOVO_X200:
1963 spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; 1971 spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
@@ -1965,7 +1973,11 @@ static int patch_cxt5051(struct hda_codec *codec)
1965 case CXT5051_F700: 1973 case CXT5051_F700:
1966 spec->init_verbs[0] = cxt5051_f700_init_verbs; 1974 spec->init_verbs[0] = cxt5051_f700_init_verbs;
1967 spec->mixers[0] = cxt5051_f700_mixers; 1975 spec->mixers[0] = cxt5051_f700_mixers;
1968 spec->no_auto_mic = 1; 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;
1969 break; 1981 break;
1970 } 1982 }
1971 1983
@@ -2156,6 +2168,34 @@ static void cxt5066_vostro_automic(struct hda_codec *codec)
2156 } 2168 }
2157} 2169}
2158 2170
2171/* toggle input of built-in digital mic and mic jack appropriately */
2172static void cxt5066_ideapad_automic(struct hda_codec *codec)
2173{
2174 unsigned int present;
2175
2176 struct hda_verb ext_mic_present[] = {
2177 {0x14, AC_VERB_SET_CONNECT_SEL, 0},
2178 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2179 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2180 {}
2181 };
2182 static struct hda_verb ext_mic_absent[] = {
2183 {0x14, AC_VERB_SET_CONNECT_SEL, 2},
2184 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2185 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2186 {}
2187 };
2188
2189 present = snd_hda_jack_detect(codec, 0x1b);
2190 if (present) {
2191 snd_printdd("CXT5066: external microphone detected\n");
2192 snd_hda_sequence_write(codec, ext_mic_present);
2193 } else {
2194 snd_printdd("CXT5066: external microphone absent\n");
2195 snd_hda_sequence_write(codec, ext_mic_absent);
2196 }
2197}
2198
2159/* mute internal speaker if HP is plugged */ 2199/* mute internal speaker if HP is plugged */
2160static void cxt5066_hp_automute(struct hda_codec *codec) 2200static void cxt5066_hp_automute(struct hda_codec *codec)
2161{ 2201{
@@ -2205,6 +2245,20 @@ static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res)
2205 } 2245 }
2206} 2246}
2207 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
2208static const struct hda_input_mux cxt5066_analog_mic_boost = { 2262static const struct hda_input_mux cxt5066_analog_mic_boost = {
2209 .num_items = 5, 2263 .num_items = 5,
2210 .items = { 2264 .items = {
@@ -2216,13 +2270,21 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = {
2216 }, 2270 },
2217}; 2271};
2218 2272
2219static int cxt5066_set_mic_boost(struct hda_codec *codec) 2273static void cxt5066_set_mic_boost(struct hda_codec *codec)
2220{ 2274{
2221 struct conexant_spec *spec = codec->spec; 2275 struct conexant_spec *spec = codec->spec;
2222 return snd_hda_codec_write_cache(codec, 0x17, 0, 2276 snd_hda_codec_write_cache(codec, 0x17, 0,
2223 AC_VERB_SET_AMP_GAIN_MUTE, 2277 AC_VERB_SET_AMP_GAIN_MUTE,
2224 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | 2278 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
2225 cxt5066_analog_mic_boost.items[spec->mic_boost].index); 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 }
2226} 2288}
2227 2289
2228static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, 2290static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol,
@@ -2653,6 +2715,56 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = {
2653 { } /* end */ 2715 { } /* end */
2654}; 2716};
2655 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
2656static struct hda_verb cxt5066_init_verbs_portd_lo[] = { 2768static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
2657 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2769 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2658 { } /* end */ 2770 { } /* end */
@@ -2669,6 +2781,8 @@ static int cxt5066_init(struct hda_codec *codec)
2669 cxt5066_hp_automute(codec); 2781 cxt5066_hp_automute(codec);
2670 if (spec->dell_vostro) 2782 if (spec->dell_vostro)
2671 cxt5066_vostro_automic(codec); 2783 cxt5066_vostro_automic(codec);
2784 else if (spec->ideapad)
2785 cxt5066_ideapad_automic(codec);
2672 } 2786 }
2673 cxt5066_set_mic_boost(codec); 2787 cxt5066_set_mic_boost(codec);
2674 return 0; 2788 return 0;
@@ -2694,6 +2808,7 @@ enum {
2694 CXT5066_DELL_LAPTOP, /* Dell Laptop */ 2808 CXT5066_DELL_LAPTOP, /* Dell Laptop */
2695 CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ 2809 CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
2696 CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ 2810 CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */
2811 CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
2697 CXT5066_MODELS 2812 CXT5066_MODELS
2698}; 2813};
2699 2814
@@ -2701,7 +2816,8 @@ static const char *cxt5066_models[CXT5066_MODELS] = {
2701 [CXT5066_LAPTOP] = "laptop", 2816 [CXT5066_LAPTOP] = "laptop",
2702 [CXT5066_DELL_LAPTOP] = "dell-laptop", 2817 [CXT5066_DELL_LAPTOP] = "dell-laptop",
2703 [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", 2818 [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
2704 [CXT5066_DELL_VOSTO] = "dell-vostro" 2819 [CXT5066_DELL_VOSTO] = "dell-vostro",
2820 [CXT5066_IDEAPAD] = "ideapad",
2705}; 2821};
2706 2822
2707static struct snd_pci_quirk cxt5066_cfg_tbl[] = { 2823static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
@@ -2711,6 +2827,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
2711 CXT5066_DELL_LAPTOP), 2827 CXT5066_DELL_LAPTOP),
2712 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),
2713 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),
2714 {} 2831 {}
2715}; 2832};
2716 2833
@@ -2802,6 +2919,22 @@ static int patch_cxt5066(struct hda_codec *codec)
2802 /* input source automatically selected */ 2919 /* input source automatically selected */
2803 spec->input_mux = NULL; 2920 spec->input_mux = NULL;
2804 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;
2805 } 2938 }
2806 2939
2807 return 0; 2940 return 0;