diff options
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 255 |
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 | ||
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,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 | ||
1690 | static struct snd_kcontrol_new cxt5051_mixers[] = { | 1698 | static 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 | ||
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), | ||
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 | ||
1728 | static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { | 1729 | static 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 | ||
1744 | static struct snd_kcontrol_new cxt5051_f700_mixers[] = { | 1735 | static 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 | ||
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), | ||
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 | ||
1850 | static struct hda_verb cxt5051_f700_init_verbs[] = { | 1834 | static 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 | ||
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 | |||
1876 | /* initialize jack-sensing, too */ | 1871 | /* initialize jack-sensing, too */ |
1877 | static int cxt5051_init(struct hda_codec *codec) | 1872 | static 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 | ||
1907 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1912 | static 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 */ | ||
2172 | static 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 */ |
2160 | static void cxt5066_hp_automute(struct hda_codec *codec) | 2200 | static 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 */ | ||
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 | |||
2208 | static const struct hda_input_mux cxt5066_analog_mic_boost = { | 2262 | static 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 | ||
2219 | static int cxt5066_set_mic_boost(struct hda_codec *codec) | 2273 | static 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 | ||
2228 | 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, |
@@ -2653,6 +2715,56 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = { | |||
2653 | { } /* end */ | 2715 | { } /* end */ |
2654 | }; | 2716 | }; |
2655 | 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 | |||
2656 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { | 2768 | static 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 | ||
2707 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | 2823 | static 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; |