Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 182653
b: refs/heads/master
c: 75f8991
h: refs/heads/master
i:
  182651: 7d728e0
v: v3
  • Loading branch information
Daniel Drake authored and Jaroslav Kysela committed Jan 8, 2010
1 parent af91b18 commit 59352ee
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 41 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a4ad68d57e4dc4138304df23d1817eb094149389
refs/heads/master: 75f8991d0e6969407d51501d5a0537f104075c99
125 changes: 85 additions & 40 deletions trunk/sound/pci/hda/patch_conexant.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,12 @@ struct conexant_spec {

unsigned int dell_automute;
unsigned int port_d_mode;
unsigned char ext_mic_bias;
unsigned int dell_vostro;

unsigned int ext_mic_present;
unsigned int recording;
void (*capture_prepare)(struct hda_codec *codec);
void (*capture_cleanup)(struct hda_codec *codec);
};

static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
Expand Down Expand Up @@ -185,6 +189,8 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
struct conexant_spec *spec = codec->spec;
if (spec->capture_prepare)
spec->capture_prepare(codec);
snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
stream_tag, 0, format);
return 0;
Expand All @@ -196,6 +202,8 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
{
struct conexant_spec *spec = codec->spec;
snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
if (spec->capture_cleanup)
spec->capture_cleanup(codec);
return 0;
}

Expand Down Expand Up @@ -2016,53 +2024,53 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
return 1;
}

/* toggle input of built-in and mic jack appropriately */
static void cxt5066_automic(struct hda_codec *codec)
/* OLPC defers mic widget control until when capture is started because the
* microphone LED comes on as soon as these settings are put in place. if we
* did this before recording, it would give the false indication that recording
* is happening when it is not. */
static void cxt5066_olpc_select_mic(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
struct hda_verb ext_mic_present[] = {
/* enable external mic, port B */
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias},

/* switch to external mic input */
{0x17, AC_VERB_SET_CONNECT_SEL, 0},
if (!spec->recording)
return;

/* disable internal mic, port C */
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
{}
};
static struct hda_verb ext_mic_absent[] = {
/* enable internal mic, port C */
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
/* external mic, port B */
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);

/* switch to internal mic input */
{0x17, AC_VERB_SET_CONNECT_SEL, 1},
/* internal mic, port C */
snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
spec->ext_mic_present ? 0 : PIN_VREF80);
}

/* disable external mic, port B */
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
{}
};
/* toggle input of built-in and mic jack appropriately */
static void cxt5066_olpc_automic(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
unsigned int present;

present = snd_hda_jack_detect(codec, 0x1a);
if (present) {
present = snd_hda_codec_read(codec, 0x1a, 0,
AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
if (present)
snd_printdd("CXT5066: external microphone detected\n");
snd_hda_sequence_write(codec, ext_mic_present);
} else {
else
snd_printdd("CXT5066: external microphone absent\n");
snd_hda_sequence_write(codec, ext_mic_absent);
}

snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
present ? 0 : 1);
spec->ext_mic_present = !!present;

cxt5066_olpc_select_mic(codec);
}

/* toggle input of built-in digital mic and mic jack appropriately */
static void cxt5066_vostro_automic(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
unsigned int present;

struct hda_verb ext_mic_present[] = {
/* enable external mic, port B */
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias},
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},

/* switch to external mic input */
{0x17, AC_VERB_SET_CONNECT_SEL, 0},
Expand Down Expand Up @@ -2113,15 +2121,15 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
}

/* unsolicited event for jack sensing */
static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
{
snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
switch (res >> 26) {
case CONEXANT_HP_EVENT:
cxt5066_hp_automute(codec);
break;
case CONEXANT_MIC_EVENT:
cxt5066_automic(codec);
cxt5066_olpc_automic(codec);
break;
}
}
Expand Down Expand Up @@ -2197,6 +2205,31 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
return 1;
}

static void cxt5066_olpc_capture_prepare(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
/* mark as recording and configure the microphone widget so that the
* recording LED comes on. */
spec->recording = 1;
cxt5066_olpc_select_mic(codec);
}

static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
const struct hda_verb disable_mics[] = {
/* disable external mic, port B */
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},

/* disble internal mic, port C */
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
{},
};

snd_hda_sequence_write(codec, disable_mics);
spec->recording = 0;
}

static struct hda_input_mux cxt5066_capture_source = {
.num_items = 4,
.items = {
Expand Down Expand Up @@ -2347,10 +2380,10 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */

/* Port B: external microphone */
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS},
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},

/* Port C: internal microphone */
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},

/* Port D: unused */
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Expand Down Expand Up @@ -2479,12 +2512,19 @@ static int cxt5066_init(struct hda_codec *codec)
cxt5066_hp_automute(codec);
if (spec->dell_vostro)
cxt5066_vostro_automic(codec);
else
cxt5066_automic(codec);
}
return 0;
}

static int cxt5066_olpc_init(struct hda_codec *codec)
{
snd_printdd("CXT5066: init\n");
conexant_init(codec);
cxt5066_hp_automute(codec);
cxt5066_olpc_automic(codec);
return 0;
}

enum {
CXT5066_LAPTOP, /* Laptops w/ EAPD support */
CXT5066_DELL_LAPTOP, /* Dell Laptop */
Expand Down Expand Up @@ -2521,7 +2561,7 @@ static int patch_cxt5066(struct hda_codec *codec)
codec->spec = spec;

codec->patch_ops = conexant_patch_ops;
codec->patch_ops.init = cxt5066_init;
codec->patch_ops.init = conexant_init;

spec->dell_automute = 0;
spec->multiout.max_channels = 2;
Expand All @@ -2534,7 +2574,6 @@ static int patch_cxt5066(struct hda_codec *codec)
spec->input_mux = &cxt5066_capture_source;

spec->port_d_mode = PIN_HP;
spec->ext_mic_bias = PIN_VREF80;

spec->num_init_verbs = 1;
spec->init_verbs[0] = cxt5066_init_verbs;
Expand All @@ -2561,20 +2600,26 @@ static int patch_cxt5066(struct hda_codec *codec)
spec->dell_automute = 1;
break;
case CXT5066_OLPC_XO_1_5:
codec->patch_ops.unsol_event = cxt5066_unsol_event;
codec->patch_ops.init = cxt5066_olpc_init;
codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event;
spec->init_verbs[0] = cxt5066_init_verbs_olpc;
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
spec->port_d_mode = 0;
spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS;

/* no S/PDIF out */
spec->multiout.dig_out_nid = 0;

/* input source automatically selected */
spec->input_mux = NULL;

/* our capture hooks which allow us to turn on the microphone LED
* at the right time */
spec->capture_prepare = cxt5066_olpc_capture_prepare;
spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
break;
case CXT5066_DELL_VOSTO:
codec->patch_ops.init = cxt5066_init;
codec->patch_ops.unsol_event = cxt5066_vostro_event;
spec->init_verbs[0] = cxt5066_init_verbs_vostro;
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
Expand Down

0 comments on commit 59352ee

Please sign in to comment.