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.c383
1 files changed, 323 insertions, 60 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index c578c28f368..685015a5329 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -111,8 +111,22 @@ struct conexant_spec {
111 111
112 unsigned int dell_automute; 112 unsigned int dell_automute;
113 unsigned int port_d_mode; 113 unsigned int port_d_mode;
114 unsigned char ext_mic_bias;
115 unsigned int dell_vostro; 114 unsigned int dell_vostro;
115
116 unsigned int ext_mic_present;
117 unsigned int recording;
118 void (*capture_prepare)(struct hda_codec *codec);
119 void (*capture_cleanup)(struct hda_codec *codec);
120
121 /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
122 * through the microphone jack.
123 * When the user enables this through a mixer switch, both internal and
124 * external microphones are disabled. Gain is fixed at 0dB. In this mode,
125 * we also allow the bias to be configured through a separate mixer
126 * control. */
127 unsigned int dc_enable;
128 unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */
129 unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
116}; 130};
117 131
118static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, 132static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -185,6 +199,8 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
185 struct snd_pcm_substream *substream) 199 struct snd_pcm_substream *substream)
186{ 200{
187 struct conexant_spec *spec = codec->spec; 201 struct conexant_spec *spec = codec->spec;
202 if (spec->capture_prepare)
203 spec->capture_prepare(codec);
188 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 204 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
189 stream_tag, 0, format); 205 stream_tag, 0, format);
190 return 0; 206 return 0;
@@ -196,6 +212,8 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
196{ 212{
197 struct conexant_spec *spec = codec->spec; 213 struct conexant_spec *spec = codec->spec;
198 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); 214 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
215 if (spec->capture_cleanup)
216 spec->capture_cleanup(codec);
199 return 0; 217 return 0;
200} 218}
201 219
@@ -1723,6 +1741,22 @@ static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
1723 {} 1741 {}
1724}; 1742};
1725 1743
1744static struct snd_kcontrol_new cxt5051_f700_mixers[] = {
1745 HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
1746 HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
1747 HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
1748 {
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
1757 {}
1758};
1759
1726static struct hda_verb cxt5051_init_verbs[] = { 1760static struct hda_verb cxt5051_init_verbs[] = {
1727 /* Line in, Mic */ 1761 /* Line in, Mic */
1728 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, 1762 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
@@ -1813,6 +1847,32 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
1813 { } /* end */ 1847 { } /* end */
1814}; 1848};
1815 1849
1850static struct hda_verb cxt5051_f700_init_verbs[] = {
1851 /* Line in, Mic */
1852 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x03},
1853 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1854 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
1855 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
1856 /* SPK */
1857 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1858 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
1859 /* HP, Amp */
1860 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1861 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
1862 /* DAC1 */
1863 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1864 /* Record selector: Int mic */
1865 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
1866 {0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
1867 /* SPDIF route: PCM */
1868 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
1869 /* EAPD */
1870 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
1871 {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 */
1874};
1875
1816/* initialize jack-sensing, too */ 1876/* initialize jack-sensing, too */
1817static int cxt5051_init(struct hda_codec *codec) 1877static int cxt5051_init(struct hda_codec *codec)
1818{ 1878{
@@ -1832,6 +1892,7 @@ enum {
1832 CXT5051_HP, /* no docking */ 1892 CXT5051_HP, /* no docking */
1833 CXT5051_HP_DV6736, /* HP without mic switch */ 1893 CXT5051_HP_DV6736, /* HP without mic switch */
1834 CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ 1894 CXT5051_LENOVO_X200, /* Lenovo X200 laptop */
1895 CXT5051_F700, /* HP Compaq Presario F700 */
1835 CXT5051_MODELS 1896 CXT5051_MODELS
1836}; 1897};
1837 1898
@@ -1840,6 +1901,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = {
1840 [CXT5051_HP] = "hp", 1901 [CXT5051_HP] = "hp",
1841 [CXT5051_HP_DV6736] = "hp-dv6736", 1902 [CXT5051_HP_DV6736] = "hp-dv6736",
1842 [CXT5051_LENOVO_X200] = "lenovo-x200", 1903 [CXT5051_LENOVO_X200] = "lenovo-x200",
1904 [CXT5051_F700] = "hp 700"
1843}; 1905};
1844 1906
1845static struct snd_pci_quirk cxt5051_cfg_tbl[] = { 1907static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
@@ -1849,6 +1911,7 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
1849 CXT5051_LAPTOP), 1911 CXT5051_LAPTOP),
1850 SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), 1912 SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
1851 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), 1913 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
1914 SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700),
1852 {} 1915 {}
1853}; 1916};
1854 1917
@@ -1899,6 +1962,11 @@ static int patch_cxt5051(struct hda_codec *codec)
1899 case CXT5051_LENOVO_X200: 1962 case CXT5051_LENOVO_X200:
1900 spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; 1963 spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
1901 break; 1964 break;
1965 case CXT5051_F700:
1966 spec->init_verbs[0] = cxt5051_f700_init_verbs;
1967 spec->mixers[0] = cxt5051_f700_mixers;
1968 spec->no_auto_mic = 1;
1969 break;
1902 } 1970 }
1903 1971
1904 return 0; 1972 return 0;
@@ -1966,53 +2034,97 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1966 return 1; 2034 return 1;
1967} 2035}
1968 2036
1969/* toggle input of built-in and mic jack appropriately */ 2037static const struct hda_input_mux cxt5066_olpc_dc_bias = {
1970static void cxt5066_automic(struct hda_codec *codec) 2038 .num_items = 3,
2039 .items = {
2040 { "Off", PIN_IN },
2041 { "50%", PIN_VREF50 },
2042 { "80%", PIN_VREF80 },
2043 },
2044};
2045
2046static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
1971{ 2047{
1972 struct conexant_spec *spec = codec->spec; 2048 struct conexant_spec *spec = codec->spec;
1973 struct hda_verb ext_mic_present[] = { 2049 /* Even though port F is the DC input, the bias is controlled on port B.
1974 /* enable external mic, port B */ 2050 * we also leave that port as an active input (but unselected) in DC mode
1975 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, 2051 * just in case that is necessary to make the bias setting take effect. */
2052 return snd_hda_codec_write_cache(codec, 0x1a, 0,
2053 AC_VERB_SET_PIN_WIDGET_CONTROL,
2054 cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
2055}
1976 2056
1977 /* switch to external mic input */ 2057/* OLPC defers mic widget control until when capture is started because the
1978 {0x17, AC_VERB_SET_CONNECT_SEL, 0}, 2058 * microphone LED comes on as soon as these settings are put in place. if we
2059 * did this before recording, it would give the false indication that recording
2060 * is happening when it is not. */
2061static void cxt5066_olpc_select_mic(struct hda_codec *codec)
2062{
2063 struct conexant_spec *spec = codec->spec;
2064 if (!spec->recording)
2065 return;
1979 2066
1980 /* disable internal mic, port C */ 2067 if (spec->dc_enable) {
1981 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2068 /* in DC mode we ignore presence detection and just use the jack
1982 {} 2069 * through our special DC port */
1983 }; 2070 const struct hda_verb enable_dc_mode[] = {
1984 static struct hda_verb ext_mic_absent[] = { 2071 /* disble internal mic, port C */
1985 /* enable internal mic, port C */ 2072 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
1986 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2073
2074 /* enable DC capture, port F */
2075 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2076 {},
2077 };
2078
2079 snd_hda_sequence_write(codec, enable_dc_mode);
2080 /* port B input disabled (and bias set) through the following call */
2081 cxt5066_set_olpc_dc_bias(codec);
2082 return;
2083 }
1987 2084
1988 /* switch to internal mic input */ 2085 /* disable DC (port F) */
1989 {0x17, AC_VERB_SET_CONNECT_SEL, 1}, 2086 snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
1990 2087
1991 /* disable external mic, port B */ 2088 /* external mic, port B */
1992 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2089 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
1993 {} 2090 spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
1994 }; 2091
2092 /* internal mic, port C */
2093 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2094 spec->ext_mic_present ? 0 : PIN_VREF80);
2095}
2096
2097/* toggle input of built-in and mic jack appropriately */
2098static void cxt5066_olpc_automic(struct hda_codec *codec)
2099{
2100 struct conexant_spec *spec = codec->spec;
1995 unsigned int present; 2101 unsigned int present;
1996 2102
1997 present = snd_hda_jack_detect(codec, 0x1a); 2103 if (spec->dc_enable) /* don't do presence detection in DC mode */
1998 if (present) { 2104 return;
2105
2106 present = snd_hda_codec_read(codec, 0x1a, 0,
2107 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
2108 if (present)
1999 snd_printdd("CXT5066: external microphone detected\n"); 2109 snd_printdd("CXT5066: external microphone detected\n");
2000 snd_hda_sequence_write(codec, ext_mic_present); 2110 else
2001 } else {
2002 snd_printdd("CXT5066: external microphone absent\n"); 2111 snd_printdd("CXT5066: external microphone absent\n");
2003 snd_hda_sequence_write(codec, ext_mic_absent); 2112
2004 } 2113 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
2114 present ? 0 : 1);
2115 spec->ext_mic_present = !!present;
2116
2117 cxt5066_olpc_select_mic(codec);
2005} 2118}
2006 2119
2007/* toggle input of built-in digital mic and mic jack appropriately */ 2120/* toggle input of built-in digital mic and mic jack appropriately */
2008static void cxt5066_vostro_automic(struct hda_codec *codec) 2121static void cxt5066_vostro_automic(struct hda_codec *codec)
2009{ 2122{
2010 struct conexant_spec *spec = codec->spec;
2011 unsigned int present; 2123 unsigned int present;
2012 2124
2013 struct hda_verb ext_mic_present[] = { 2125 struct hda_verb ext_mic_present[] = {
2014 /* enable external mic, port B */ 2126 /* enable external mic, port B */
2015 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, 2127 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2016 2128
2017 /* switch to external mic input */ 2129 /* switch to external mic input */
2018 {0x17, AC_VERB_SET_CONNECT_SEL, 0}, 2130 {0x17, AC_VERB_SET_CONNECT_SEL, 0},
@@ -2063,15 +2175,18 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
2063} 2175}
2064 2176
2065/* unsolicited event for jack sensing */ 2177/* unsolicited event for jack sensing */
2066static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) 2178static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
2067{ 2179{
2180 struct conexant_spec *spec = codec->spec;
2068 snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); 2181 snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
2069 switch (res >> 26) { 2182 switch (res >> 26) {
2070 case CONEXANT_HP_EVENT: 2183 case CONEXANT_HP_EVENT:
2071 cxt5066_hp_automute(codec); 2184 cxt5066_hp_automute(codec);
2072 break; 2185 break;
2073 case CONEXANT_MIC_EVENT: 2186 case CONEXANT_MIC_EVENT:
2074 cxt5066_automic(codec); 2187 /* ignore mic events in DC mode; we're always using the jack */
2188 if (!spec->dc_enable)
2189 cxt5066_olpc_automic(codec);
2075 break; 2190 break;
2076 } 2191 }
2077} 2192}
@@ -2101,6 +2216,15 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = {
2101 }, 2216 },
2102}; 2217};
2103 2218
2219static int cxt5066_set_mic_boost(struct hda_codec *codec)
2220{
2221 struct conexant_spec *spec = codec->spec;
2222 return snd_hda_codec_write_cache(codec, 0x17, 0,
2223 AC_VERB_SET_AMP_GAIN_MUTE,
2224 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
2225 cxt5066_analog_mic_boost.items[spec->mic_boost].index);
2226}
2227
2104static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, 2228static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol,
2105 struct snd_ctl_elem_info *uinfo) 2229 struct snd_ctl_elem_info *uinfo)
2106{ 2230{
@@ -2111,15 +2235,8 @@ static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol,
2111 struct snd_ctl_elem_value *ucontrol) 2235 struct snd_ctl_elem_value *ucontrol)
2112{ 2236{
2113 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2237 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2114 int val; 2238 struct conexant_spec *spec = codec->spec;
2115 hda_nid_t nid = kcontrol->private_value & 0xff; 2239 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; 2240 return 0;
2124} 2241}
2125 2242
@@ -2127,26 +2244,132 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
2127 struct snd_ctl_elem_value *ucontrol) 2244 struct snd_ctl_elem_value *ucontrol)
2128{ 2245{
2129 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2246 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2247 struct conexant_spec *spec = codec->spec;
2130 const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; 2248 const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
2131 unsigned int idx; 2249 unsigned int idx;
2132 hda_nid_t nid = kcontrol->private_value & 0xff; 2250 idx = ucontrol->value.enumerated.item[0];
2133 int inout = (kcontrol->private_value & 0x100) ? 2251 if (idx >= imux->num_items)
2134 AC_AMP_SET_INPUT : AC_AMP_SET_OUTPUT; 2252 idx = imux->num_items - 1;
2253
2254 spec->mic_boost = idx;
2255 if (!spec->dc_enable)
2256 cxt5066_set_mic_boost(codec);
2257 return 1;
2258}
2259
2260static void cxt5066_enable_dc(struct hda_codec *codec)
2261{
2262 const struct hda_verb enable_dc_mode[] = {
2263 /* disable gain */
2264 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2265
2266 /* switch to DC input */
2267 {0x17, AC_VERB_SET_CONNECT_SEL, 3},
2268 {}
2269 };
2270
2271 /* configure as input source */
2272 snd_hda_sequence_write(codec, enable_dc_mode);
2273 cxt5066_olpc_select_mic(codec); /* also sets configured bias */
2274}
2275
2276static void cxt5066_disable_dc(struct hda_codec *codec)
2277{
2278 /* reconfigure input source */
2279 cxt5066_set_mic_boost(codec);
2280 /* automic also selects the right mic if we're recording */
2281 cxt5066_olpc_automic(codec);
2282}
2283
2284static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol,
2285 struct snd_ctl_elem_value *ucontrol)
2286{
2287 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2288 struct conexant_spec *spec = codec->spec;
2289 ucontrol->value.integer.value[0] = spec->dc_enable;
2290 return 0;
2291}
2292
2293static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol,
2294 struct snd_ctl_elem_value *ucontrol)
2295{
2296 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2297 struct conexant_spec *spec = codec->spec;
2298 int dc_enable = !!ucontrol->value.integer.value[0];
2135 2299
2136 if (!imux->num_items) 2300 if (dc_enable == spec->dc_enable)
2137 return 0; 2301 return 0;
2302
2303 spec->dc_enable = dc_enable;
2304 if (dc_enable)
2305 cxt5066_enable_dc(codec);
2306 else
2307 cxt5066_disable_dc(codec);
2308
2309 return 1;
2310}
2311
2312static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
2313 struct snd_ctl_elem_info *uinfo)
2314{
2315 return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo);
2316}
2317
2318static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
2319 struct snd_ctl_elem_value *ucontrol)
2320{
2321 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2322 struct conexant_spec *spec = codec->spec;
2323 ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
2324 return 0;
2325}
2326
2327static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
2328 struct snd_ctl_elem_value *ucontrol)
2329{
2330 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2331 struct conexant_spec *spec = codec->spec;
2332 const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
2333 unsigned int idx;
2334
2138 idx = ucontrol->value.enumerated.item[0]; 2335 idx = ucontrol->value.enumerated.item[0];
2139 if (idx >= imux->num_items) 2336 if (idx >= imux->num_items)
2140 idx = imux->num_items - 1; 2337 idx = imux->num_items - 1;
2141 2338
2142 snd_hda_codec_write_cache(codec, nid, 0, 2339 spec->dc_input_bias = idx;
2143 AC_VERB_SET_AMP_GAIN_MUTE, 2340 if (spec->dc_enable)
2144 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | inout | 2341 cxt5066_set_olpc_dc_bias(codec);
2145 imux->items[idx].index);
2146
2147 return 1; 2342 return 1;
2148} 2343}
2149 2344
2345static void cxt5066_olpc_capture_prepare(struct hda_codec *codec)
2346{
2347 struct conexant_spec *spec = codec->spec;
2348 /* mark as recording and configure the microphone widget so that the
2349 * recording LED comes on. */
2350 spec->recording = 1;
2351 cxt5066_olpc_select_mic(codec);
2352}
2353
2354static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
2355{
2356 struct conexant_spec *spec = codec->spec;
2357 const struct hda_verb disable_mics[] = {
2358 /* disable external mic, port B */
2359 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2360
2361 /* disble internal mic, port C */
2362 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2363
2364 /* disable DC capture, port F */
2365 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2366 {},
2367 };
2368
2369 snd_hda_sequence_write(codec, disable_mics);
2370 spec->recording = 0;
2371}
2372
2150static struct hda_input_mux cxt5066_capture_source = { 2373static struct hda_input_mux cxt5066_capture_source = {
2151 .num_items = 4, 2374 .num_items = 4,
2152 .items = { 2375 .items = {
@@ -2187,6 +2410,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
2187 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 2410 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
2188 SNDRV_CTL_ELEM_ACCESS_TLV_READ | 2411 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
2189 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, 2412 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
2413 .subdevice = HDA_SUBDEV_AMP_FLAG,
2190 .info = snd_hda_mixer_amp_volume_info, 2414 .info = snd_hda_mixer_amp_volume_info,
2191 .get = snd_hda_mixer_amp_volume_get, 2415 .get = snd_hda_mixer_amp_volume_get,
2192 .put = snd_hda_mixer_amp_volume_put, 2416 .put = snd_hda_mixer_amp_volume_put,
@@ -2198,6 +2422,24 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
2198 {} 2422 {}
2199}; 2423};
2200 2424
2425static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
2426 {
2427 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2428 .name = "DC Mode Enable Switch",
2429 .info = snd_ctl_boolean_mono_info,
2430 .get = cxt5066_olpc_dc_get,
2431 .put = cxt5066_olpc_dc_put,
2432 },
2433 {
2434 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2435 .name = "DC Input Bias Enum",
2436 .info = cxt5066_olpc_dc_bias_enum_info,
2437 .get = cxt5066_olpc_dc_bias_enum_get,
2438 .put = cxt5066_olpc_dc_bias_enum_put,
2439 },
2440 {}
2441};
2442
2201static struct snd_kcontrol_new cxt5066_mixers[] = { 2443static struct snd_kcontrol_new cxt5066_mixers[] = {
2202 { 2444 {
2203 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2445 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2210,11 +2452,10 @@ static struct snd_kcontrol_new cxt5066_mixers[] = {
2210 2452
2211 { 2453 {
2212 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2454 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2213 .name = "Ext Mic Boost Capture Enum", 2455 .name = "Analog Mic Boost Capture Enum",
2214 .info = cxt5066_mic_boost_mux_enum_info, 2456 .info = cxt5066_mic_boost_mux_enum_info,
2215 .get = cxt5066_mic_boost_mux_enum_get, 2457 .get = cxt5066_mic_boost_mux_enum_get,
2216 .put = cxt5066_mic_boost_mux_enum_put, 2458 .put = cxt5066_mic_boost_mux_enum_put,
2217 .private_value = 0x17,
2218 }, 2459 },
2219 2460
2220 HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), 2461 HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others),
@@ -2296,10 +2537,10 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
2296 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2537 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2297 2538
2298 /* Port B: external microphone */ 2539 /* Port B: external microphone */
2299 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, 2540 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2300 2541
2301 /* Port C: internal microphone */ 2542 /* Port C: internal microphone */
2302 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2543 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2303 2544
2304 /* Port D: unused */ 2545 /* Port D: unused */
2305 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2546 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -2308,7 +2549,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
2308 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2549 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2309 {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 2550 {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
2310 2551
2311 /* Port F: unused */ 2552 /* Port F: external DC input through microphone port */
2312 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2553 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2313 2554
2314 /* Port G: internal speakers */ 2555 /* Port G: internal speakers */
@@ -2428,8 +2669,22 @@ static int cxt5066_init(struct hda_codec *codec)
2428 cxt5066_hp_automute(codec); 2669 cxt5066_hp_automute(codec);
2429 if (spec->dell_vostro) 2670 if (spec->dell_vostro)
2430 cxt5066_vostro_automic(codec); 2671 cxt5066_vostro_automic(codec);
2431 else 2672 }
2432 cxt5066_automic(codec); 2673 cxt5066_set_mic_boost(codec);
2674 return 0;
2675}
2676
2677static int cxt5066_olpc_init(struct hda_codec *codec)
2678{
2679 struct conexant_spec *spec = codec->spec;
2680 snd_printdd("CXT5066: init\n");
2681 conexant_init(codec);
2682 cxt5066_hp_automute(codec);
2683 if (!spec->dc_enable) {
2684 cxt5066_set_mic_boost(codec);
2685 cxt5066_olpc_automic(codec);
2686 } else {
2687 cxt5066_enable_dc(codec);
2433 } 2688 }
2434 return 0; 2689 return 0;
2435} 2690}
@@ -2470,7 +2725,7 @@ static int patch_cxt5066(struct hda_codec *codec)
2470 codec->spec = spec; 2725 codec->spec = spec;
2471 2726
2472 codec->patch_ops = conexant_patch_ops; 2727 codec->patch_ops = conexant_patch_ops;
2473 codec->patch_ops.init = cxt5066_init; 2728 codec->patch_ops.init = conexant_init;
2474 2729
2475 spec->dell_automute = 0; 2730 spec->dell_automute = 0;
2476 spec->multiout.max_channels = 2; 2731 spec->multiout.max_channels = 2;
@@ -2483,7 +2738,6 @@ static int patch_cxt5066(struct hda_codec *codec)
2483 spec->input_mux = &cxt5066_capture_source; 2738 spec->input_mux = &cxt5066_capture_source;
2484 2739
2485 spec->port_d_mode = PIN_HP; 2740 spec->port_d_mode = PIN_HP;
2486 spec->ext_mic_bias = PIN_VREF80;
2487 2741
2488 spec->num_init_verbs = 1; 2742 spec->num_init_verbs = 1;
2489 spec->init_verbs[0] = cxt5066_init_verbs; 2743 spec->init_verbs[0] = cxt5066_init_verbs;
@@ -2510,20 +2764,28 @@ static int patch_cxt5066(struct hda_codec *codec)
2510 spec->dell_automute = 1; 2764 spec->dell_automute = 1;
2511 break; 2765 break;
2512 case CXT5066_OLPC_XO_1_5: 2766 case CXT5066_OLPC_XO_1_5:
2513 codec->patch_ops.unsol_event = cxt5066_unsol_event; 2767 codec->patch_ops.init = cxt5066_olpc_init;
2768 codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event;
2514 spec->init_verbs[0] = cxt5066_init_verbs_olpc; 2769 spec->init_verbs[0] = cxt5066_init_verbs_olpc;
2515 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; 2770 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
2771 spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc;
2516 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 2772 spec->mixers[spec->num_mixers++] = cxt5066_mixers;
2517 spec->port_d_mode = 0; 2773 spec->port_d_mode = 0;
2518 spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS; 2774 spec->mic_boost = 3; /* default 30dB gain */
2519 2775
2520 /* no S/PDIF out */ 2776 /* no S/PDIF out */
2521 spec->multiout.dig_out_nid = 0; 2777 spec->multiout.dig_out_nid = 0;
2522 2778
2523 /* input source automatically selected */ 2779 /* input source automatically selected */
2524 spec->input_mux = NULL; 2780 spec->input_mux = NULL;
2781
2782 /* our capture hooks which allow us to turn on the microphone LED
2783 * at the right time */
2784 spec->capture_prepare = cxt5066_olpc_capture_prepare;
2785 spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
2525 break; 2786 break;
2526 case CXT5066_DELL_VOSTO: 2787 case CXT5066_DELL_VOSTO:
2788 codec->patch_ops.init = cxt5066_init;
2527 codec->patch_ops.unsol_event = cxt5066_vostro_event; 2789 codec->patch_ops.unsol_event = cxt5066_vostro_event;
2528 spec->init_verbs[0] = cxt5066_init_verbs_vostro; 2790 spec->init_verbs[0] = cxt5066_init_verbs_vostro;
2529 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; 2791 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
@@ -2531,6 +2793,7 @@ static int patch_cxt5066(struct hda_codec *codec)
2531 spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; 2793 spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers;
2532 spec->port_d_mode = 0; 2794 spec->port_d_mode = 0;
2533 spec->dell_vostro = 1; 2795 spec->dell_vostro = 1;
2796 spec->mic_boost = 3; /* default 30dB gain */
2534 snd_hda_attach_beep_device(codec, 0x13); 2797 snd_hda_attach_beep_device(codec, 0x13);
2535 2798
2536 /* no S/PDIF out */ 2799 /* no S/PDIF out */