for_each_hda_codec_node(nid, codec) { if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) continue; if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) continue;
spec->eapds[spec->num_eapds++] = nid; if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) break;
}
/* NOTE: below is a wild guess; if we have more than two EAPDs, * it's a new chip, where EAPDs are supposed to be associated to * pins, and we can control EAPD per pin. * OTOH, if only one or two EAPDs are found, it's an old chip, * thus it might control over all pins.
*/ if (spec->num_eapds > 2)
spec->dynamic_eapd = 1;
}
staticvoid cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, const hda_nid_t *pins, bool on)
{ int i; for (i = 0; i < num_pins; i++) { if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
snd_hda_codec_write(codec, pins[i], 0,
AC_VERB_SET_EAPD_BTLENABLE,
on ? 0x02 : 0);
}
}
/* turn on/off EAPD according to Master switch */ staticvoid cx_auto_vmaster_hook(void *private_data, int enabled)
{ struct hda_codec *codec = private_data; struct conexant_spec *spec = codec->spec;
/* fix some headset type recognize fail issue, such as EDIFIER headset */ /* set micbias output current comparator threshold from 66% to 55%. */
snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010); /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias register * value adjustment trim from 2.2K ohms to 2.0K ohms.
*/
snd_hda_codec_write(codec, 0x1c, 0, 0x3b0, 0xe10); /* fix reboot headset type recognize fail issue */
mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); if (mic_present & AC_PINSENSE_PRESENCE) /* enable headset mic VREF */
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24); else /* disable headset mic VREF */
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
}
/* Turn the problematic codec into D3 to avoid spurious noises
from the internal speaker during (and after) reboot */
cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
}
/* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled, * the node 19 can only be configured to microphone or disabled. * Check hp&mic tag to process headset plugin & plugout.
*/
mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20); else
cx_process_headset_plugin(codec);
}
/* fix widget control pin settings */ staticvoid cxt_fixup_update_pinctl(struct hda_codec *codec, conststruct hda_fixup *fix, int action)
{ if (action == HDA_FIXUP_ACT_PROBE) { /* Unset OUT_EN for this Node pin, leaving only HP_EN. * This is the value stored in the codec register after * the correct initialization of the previous windows boot.
*/
snd_hda_set_pin_ctl_cache(codec, 0x1d, AC_PINCTL_HP_EN);
}
}
staticvoid cxt5066_increase_mic_boost(struct hda_codec *codec, conststruct hda_fixup *fix, int action)
{ if (action != HDA_FIXUP_ACT_PRE_PROBE) return;
staticvoid cxt_update_headset_mode(struct hda_codec *codec)
{ /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */ int i; bool mic_mode = false; struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->gen.autocfg;
/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) * through the microphone jack. * When the user enables this through a mixer switch, both internal and * external microphones are disabled. Gain is fixed at 0dB. In this mode, * we also allow the bias to be configured through a separate mixer
* control. */
/* Set up mic pins for port-B, C and F dynamically as the recording * LED is turned on/off by these pin controls
*/ if (!spec->dc_enable) { /* disable DC bias path and pin for port F */
update_mic_pin(codec, 0x1e, 0);
snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
/* update port B (ext mic) and C (int mic) */ /* 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.
*/
update_mic_pin(codec, 0x1a, spec->recording ?
snd_hda_codec_get_pin_target(codec, 0x1a) : 0);
update_mic_pin(codec, 0x1b, spec->recording ?
snd_hda_codec_get_pin_target(codec, 0x1b) : 0); /* enable normal mic path */
path = snd_hda_get_path_from_idx(codec, cur_input); if (path)
snd_hda_activate_path(codec, path, true, false);
} else { /* disable normal mic path */
path = snd_hda_get_path_from_idx(codec, cur_input); if (path)
snd_hda_activate_path(codec, path, false, false);
/* Even though port F is the DC input, the bias is controlled * on port B. We also leave that port as an active input (but * unselected) in DC mode just in case that is necessary to * make the bias setting take effect.
*/ if (spec->recording)
val = olpc_xo_dc_bias.items[spec->dc_input_bias].index; else
val = 0;
update_mic_pin(codec, 0x1a, val);
update_mic_pin(codec, 0x1b, 0); /* enable DC bias path and pin */
update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0);
snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
}
}
/* in DC mode, we don't handle automic */ if (!spec->dc_enable)
snd_hda_gen_mic_autoswitch(codec, jack);
olpc_xo_update_mic_pins(codec); if (spec->dc_enable)
olpc_xo_update_mic_boost(codec);
}
/* toggle spec->recording flag and update mic pins accordingly * for turning on/off LED
*/ switch (action) { case HDA_GEN_PCM_ACT_PREPARE:
spec->recording = 1;
olpc_xo_update_mic_pins(codec); break; case HDA_GEN_PCM_ACT_CLEANUP:
spec->recording = 0;
olpc_xo_update_mic_pins(codec); break;
}
}
/* OLPC's microphone port is DC coupled for use with external sensors, * therefore we use a 50% mic bias in order to center the input signal * with the DC input range of the codec.
*/
snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50);
/* override mic boost control */
snd_array_for_each(&spec->gen.kctls, i, kctl) { if (!strcmp(kctl->name, "Mic Boost Volume")) {
kctl->put = olpc_xo_mic_boost_put; break;
}
}
}
/* * Fix max input level on mixer widget to 0dB * (originally it has 0x2b steps with 0dB offset 0x14)
*/ staticvoid cxt_fixup_cap_mix_amp(struct hda_codec *codec, conststruct hda_fixup *fix, int action)
{
snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
(0x14 << AC_AMPCAP_OFFSET_SHIFT) |
(0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
(0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
(1 << AC_AMPCAP_MUTE_SHIFT));
}
/* * Fix max input level on mixer widget to 0dB * (originally it has 0x1e steps with 0 dB offset 0x17)
*/ staticvoid cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec, conststruct hda_fixup *fix, int action)
{
snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT,
(0x17 << AC_AMPCAP_OFFSET_SHIFT) |
(0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
(0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
(1 << AC_AMPCAP_MUTE_SHIFT));
}
staticvoid cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec, conststruct hda_fixup *fix, int action)
{ /* the mic pin (0x19) doesn't give an unsolicited event; * probe the mic pin together with the headphone pin (0x16)
*/ if (action == HDA_FIXUP_ACT_PROBE)
snd_hda_jack_set_gating_jack(codec, 0x19, 0x16);
}
/* update LED status via GPIO */ staticvoid cxt_update_gpio_led(struct hda_codec *codec, unsignedint mask, bool led_on)
{ struct conexant_spec *spec = codec->spec; unsignedint oldval = spec->gpio_led;
staticvoid cxt_setup_gpio_unmute(struct hda_codec *codec, unsignedint gpio_mute_mask)
{ if (gpio_mute_mask) { // set gpio data to 0.
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, gpio_mute_mask);
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, gpio_mute_mask);
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_STICKY_MASK, 0);
}
}
staticvoid cxt_fixup_mute_led_gpio(struct hda_codec *codec, conststruct hda_fixup *fix, int action)
{ if (action == HDA_FIXUP_ACT_PRE_PROBE)
cxt_setup_mute_led(codec, 0x01, 0x02);
}
staticvoid cxt_fixup_hp_zbook_mute_led(struct hda_codec *codec, conststruct hda_fixup *fix, int action)
{ if (action == HDA_FIXUP_ACT_PRE_PROBE)
cxt_setup_mute_led(codec, 0x10, 0x20);
}
staticvoid cxt_fixup_hp_a_u(struct hda_codec *codec, conststruct hda_fixup *fix, int action)
{ // Init vers in BIOS mute the spk/hp by set gpio high to avoid pop noise, // so need to unmute once by clearing the gpio data when runs into the system. if (action == HDA_FIXUP_ACT_INIT)
cxt_setup_gpio_unmute(codec, 0x2);
}
/* ThinkPad X200 & co with cxt5051 */ staticconststruct hda_pintbl cxt_pincfg_lenovo_x200[] = {
{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
{ 0x17, 0x21a11000 }, /* dock-mic */
{ 0x19, 0x2121103f }, /* dock-HP */
{ 0x1c, 0x21440100 }, /* dock SPDIF out */
{}
};
staticconststruct hda_quirk cxt5047_fixups[] = { /* HP laptops have really bad sound over 0 dB on NID 0x10.
*/
SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047),
{}
};
err = cx_auto_parse_beep(codec); if (err < 0) goto error;
err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) goto error;
/* Some laptops with Conexant chips show stalls in S3 resume, * which falls into the single-cmd mode. * Better to make reset, then.
*/ if (!codec->bus->core.sync_write) {
codec_info(codec, "Enable sync_write for stable communication\n");
codec->bus->core.sync_write = 1;
codec->bus->allow_bus_reset = 1;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.