aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/patch_conexant.c125
1 files changed, 85 insertions, 40 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 01e46ba72690..3521f33d43c3 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -111,8 +111,12 @@ 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);
116}; 120};
117 121
118static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, 122static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -185,6 +189,8 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
185 struct snd_pcm_substream *substream) 189 struct snd_pcm_substream *substream)
186{ 190{
187 struct conexant_spec *spec = codec->spec; 191 struct conexant_spec *spec = codec->spec;
192 if (spec->capture_prepare)
193 spec->capture_prepare(codec);
188 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 194 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
189 stream_tag, 0, format); 195 stream_tag, 0, format);
190 return 0; 196 return 0;
@@ -196,6 +202,8 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
196{ 202{
197 struct conexant_spec *spec = codec->spec; 203 struct conexant_spec *spec = codec->spec;
198 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); 204 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
205 if (spec->capture_cleanup)
206 spec->capture_cleanup(codec);
199 return 0; 207 return 0;
200} 208}
201 209
@@ -2016,53 +2024,53 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
2016 return 1; 2024 return 1;
2017} 2025}
2018 2026
2019/* toggle input of built-in and mic jack appropriately */ 2027/* OLPC defers mic widget control until when capture is started because the
2020static void cxt5066_automic(struct hda_codec *codec) 2028 * microphone LED comes on as soon as these settings are put in place. if we
2029 * did this before recording, it would give the false indication that recording
2030 * is happening when it is not. */
2031static void cxt5066_olpc_select_mic(struct hda_codec *codec)
2021{ 2032{
2022 struct conexant_spec *spec = codec->spec; 2033 struct conexant_spec *spec = codec->spec;
2023 struct hda_verb ext_mic_present[] = { 2034 if (!spec->recording)
2024 /* enable external mic, port B */ 2035 return;
2025 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias},
2026
2027 /* switch to external mic input */
2028 {0x17, AC_VERB_SET_CONNECT_SEL, 0},
2029 2036
2030 /* disable internal mic, port C */ 2037 /* external mic, port B */
2031 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2038 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2032 {} 2039 spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
2033 };
2034 static struct hda_verb ext_mic_absent[] = {
2035 /* enable internal mic, port C */
2036 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2037 2040
2038 /* switch to internal mic input */ 2041 /* internal mic, port C */
2039 {0x17, AC_VERB_SET_CONNECT_SEL, 1}, 2042 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2043 spec->ext_mic_present ? 0 : PIN_VREF80);
2044}
2040 2045
2041 /* disable external mic, port B */ 2046/* toggle input of built-in and mic jack appropriately */
2042 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2047static void cxt5066_olpc_automic(struct hda_codec *codec)
2043 {} 2048{
2044 }; 2049 struct conexant_spec *spec = codec->spec;
2045 unsigned int present; 2050 unsigned int present;
2046 2051
2047 present = snd_hda_jack_detect(codec, 0x1a); 2052 present = snd_hda_codec_read(codec, 0x1a, 0,
2048 if (present) { 2053 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
2054 if (present)
2049 snd_printdd("CXT5066: external microphone detected\n"); 2055 snd_printdd("CXT5066: external microphone detected\n");
2050 snd_hda_sequence_write(codec, ext_mic_present); 2056 else
2051 } else {
2052 snd_printdd("CXT5066: external microphone absent\n"); 2057 snd_printdd("CXT5066: external microphone absent\n");
2053 snd_hda_sequence_write(codec, ext_mic_absent); 2058
2054 } 2059 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
2060 present ? 0 : 1);
2061 spec->ext_mic_present = !!present;
2062
2063 cxt5066_olpc_select_mic(codec);
2055} 2064}
2056 2065
2057/* toggle input of built-in digital mic and mic jack appropriately */ 2066/* toggle input of built-in digital mic and mic jack appropriately */
2058static void cxt5066_vostro_automic(struct hda_codec *codec) 2067static void cxt5066_vostro_automic(struct hda_codec *codec)
2059{ 2068{
2060 struct conexant_spec *spec = codec->spec;
2061 unsigned int present; 2069 unsigned int present;
2062 2070
2063 struct hda_verb ext_mic_present[] = { 2071 struct hda_verb ext_mic_present[] = {
2064 /* enable external mic, port B */ 2072 /* enable external mic, port B */
2065 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, 2073 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2066 2074
2067 /* switch to external mic input */ 2075 /* switch to external mic input */
2068 {0x17, AC_VERB_SET_CONNECT_SEL, 0}, 2076 {0x17, AC_VERB_SET_CONNECT_SEL, 0},
@@ -2113,7 +2121,7 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
2113} 2121}
2114 2122
2115/* unsolicited event for jack sensing */ 2123/* unsolicited event for jack sensing */
2116static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) 2124static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
2117{ 2125{
2118 snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); 2126 snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
2119 switch (res >> 26) { 2127 switch (res >> 26) {
@@ -2121,7 +2129,7 @@ static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
2121 cxt5066_hp_automute(codec); 2129 cxt5066_hp_automute(codec);
2122 break; 2130 break;
2123 case CONEXANT_MIC_EVENT: 2131 case CONEXANT_MIC_EVENT:
2124 cxt5066_automic(codec); 2132 cxt5066_olpc_automic(codec);
2125 break; 2133 break;
2126 } 2134 }
2127} 2135}
@@ -2197,6 +2205,31 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
2197 return 1; 2205 return 1;
2198} 2206}
2199 2207
2208static void cxt5066_olpc_capture_prepare(struct hda_codec *codec)
2209{
2210 struct conexant_spec *spec = codec->spec;
2211 /* mark as recording and configure the microphone widget so that the
2212 * recording LED comes on. */
2213 spec->recording = 1;
2214 cxt5066_olpc_select_mic(codec);
2215}
2216
2217static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
2218{
2219 struct conexant_spec *spec = codec->spec;
2220 const struct hda_verb disable_mics[] = {
2221 /* disable external mic, port B */
2222 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2223
2224 /* disble internal mic, port C */
2225 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2226 {},
2227 };
2228
2229 snd_hda_sequence_write(codec, disable_mics);
2230 spec->recording = 0;
2231}
2232
2200static struct hda_input_mux cxt5066_capture_source = { 2233static struct hda_input_mux cxt5066_capture_source = {
2201 .num_items = 4, 2234 .num_items = 4,
2202 .items = { 2235 .items = {
@@ -2347,10 +2380,10 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
2347 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2380 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2348 2381
2349 /* Port B: external microphone */ 2382 /* Port B: external microphone */
2350 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, 2383 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2351 2384
2352 /* Port C: internal microphone */ 2385 /* Port C: internal microphone */
2353 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2386 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2354 2387
2355 /* Port D: unused */ 2388 /* Port D: unused */
2356 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2389 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -2479,12 +2512,19 @@ static int cxt5066_init(struct hda_codec *codec)
2479 cxt5066_hp_automute(codec); 2512 cxt5066_hp_automute(codec);
2480 if (spec->dell_vostro) 2513 if (spec->dell_vostro)
2481 cxt5066_vostro_automic(codec); 2514 cxt5066_vostro_automic(codec);
2482 else
2483 cxt5066_automic(codec);
2484 } 2515 }
2485 return 0; 2516 return 0;
2486} 2517}
2487 2518
2519static int cxt5066_olpc_init(struct hda_codec *codec)
2520{
2521 snd_printdd("CXT5066: init\n");
2522 conexant_init(codec);
2523 cxt5066_hp_automute(codec);
2524 cxt5066_olpc_automic(codec);
2525 return 0;
2526}
2527
2488enum { 2528enum {
2489 CXT5066_LAPTOP, /* Laptops w/ EAPD support */ 2529 CXT5066_LAPTOP, /* Laptops w/ EAPD support */
2490 CXT5066_DELL_LAPTOP, /* Dell Laptop */ 2530 CXT5066_DELL_LAPTOP, /* Dell Laptop */
@@ -2521,7 +2561,7 @@ static int patch_cxt5066(struct hda_codec *codec)
2521 codec->spec = spec; 2561 codec->spec = spec;
2522 2562
2523 codec->patch_ops = conexant_patch_ops; 2563 codec->patch_ops = conexant_patch_ops;
2524 codec->patch_ops.init = cxt5066_init; 2564 codec->patch_ops.init = conexant_init;
2525 2565
2526 spec->dell_automute = 0; 2566 spec->dell_automute = 0;
2527 spec->multiout.max_channels = 2; 2567 spec->multiout.max_channels = 2;
@@ -2534,7 +2574,6 @@ static int patch_cxt5066(struct hda_codec *codec)
2534 spec->input_mux = &cxt5066_capture_source; 2574 spec->input_mux = &cxt5066_capture_source;
2535 2575
2536 spec->port_d_mode = PIN_HP; 2576 spec->port_d_mode = PIN_HP;
2537 spec->ext_mic_bias = PIN_VREF80;
2538 2577
2539 spec->num_init_verbs = 1; 2578 spec->num_init_verbs = 1;
2540 spec->init_verbs[0] = cxt5066_init_verbs; 2579 spec->init_verbs[0] = cxt5066_init_verbs;
@@ -2561,20 +2600,26 @@ static int patch_cxt5066(struct hda_codec *codec)
2561 spec->dell_automute = 1; 2600 spec->dell_automute = 1;
2562 break; 2601 break;
2563 case CXT5066_OLPC_XO_1_5: 2602 case CXT5066_OLPC_XO_1_5:
2564 codec->patch_ops.unsol_event = cxt5066_unsol_event; 2603 codec->patch_ops.init = cxt5066_olpc_init;
2604 codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event;
2565 spec->init_verbs[0] = cxt5066_init_verbs_olpc; 2605 spec->init_verbs[0] = cxt5066_init_verbs_olpc;
2566 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; 2606 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
2567 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 2607 spec->mixers[spec->num_mixers++] = cxt5066_mixers;
2568 spec->port_d_mode = 0; 2608 spec->port_d_mode = 0;
2569 spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS;
2570 2609
2571 /* no S/PDIF out */ 2610 /* no S/PDIF out */
2572 spec->multiout.dig_out_nid = 0; 2611 spec->multiout.dig_out_nid = 0;
2573 2612
2574 /* input source automatically selected */ 2613 /* input source automatically selected */
2575 spec->input_mux = NULL; 2614 spec->input_mux = NULL;
2615
2616 /* our capture hooks which allow us to turn on the microphone LED
2617 * at the right time */
2618 spec->capture_prepare = cxt5066_olpc_capture_prepare;
2619 spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
2576 break; 2620 break;
2577 case CXT5066_DELL_VOSTO: 2621 case CXT5066_DELL_VOSTO:
2622 codec->patch_ops.init = cxt5066_init;
2578 codec->patch_ops.unsol_event = cxt5066_vostro_event; 2623 codec->patch_ops.unsol_event = cxt5066_vostro_event;
2579 spec->init_verbs[0] = cxt5066_init_verbs_vostro; 2624 spec->init_verbs[0] = cxt5066_init_verbs_vostro;
2580 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; 2625 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;