{
struct alc_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
- spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.suppress_auto_mute = 1;
+ break;
+ }
}
-static void alc271_fixup_dmic(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data)
{
- static const struct hda_verb verbs[] = {
- {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
- {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
- {}
- };
- unsigned int cfg;
+ struct hda_codec *cdc = data;
+ struct alc_spec *spec = cdc->spec;
- if (strcmp(codec->core.chip_name, "ALC271X") &&
- strcmp(codec->core.chip_name, "ALC269VB"))
- return;
- cfg = snd_hda_codec_get_pincfg(codec, 0x12);
- if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
- snd_hda_sequence_write(codec, verbs);
-}
+ codec_info(cdc, "ACPI Notification %d\n", event);
-/* Fix the speaker amp after resume, etc */
-static void alc269vb_fixup_aspire_e1_coef(struct hda_codec *codec,
- const struct hda_fixup *fix,
- int action)
-{
- if (action == HDA_FIXUP_ACT_INIT)
- alc_update_coef_idx(codec, 0x0d, 0x6000, 0x6000);
+ hda_component_acpi_device_notify(&spec->comps, handle, event, data);
}
-static void alc269_fixup_pcm_44k(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static int comp_bind(struct device *dev)
{
- struct alc_spec *spec = codec->spec;
+ struct hda_codec *cdc = dev_to_hda_codec(dev);
+ struct alc_spec *spec = cdc->spec;
+ int ret;
- if (action != HDA_FIXUP_ACT_PROBE)
- return;
+ ret = hda_component_manager_bind(cdc, &spec->comps);
+ if (ret)
+ return ret;
- /* Due to a hardware problem on Lenovo Ideadpad, we need to
- * fix the sample rate of analog I/O to 44.1kHz
- */
- spec->gen.stream_analog_playback = &alc269_44k_pcm_analog_playback;
- spec->gen.stream_analog_capture = &alc269_44k_pcm_analog_capture;
+ return hda_component_manager_bind_acpi_notifications(cdc,
+ &spec->comps,
+ comp_acpi_device_notify, cdc);
}
-static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void comp_unbind(struct device *dev)
{
- /* The digital-mic unit sends PDM (differential signal) instead of
- * the standard PCM, thus you can't record a valid mono stream as is.
- * Below is a workaround specific to ALC269 to control the dmic
- * signal source as mono.
- */
- if (action == HDA_FIXUP_ACT_INIT)
- alc_update_coef_idx(codec, 0x07, 0, 0x80);
+ struct hda_codec *cdc = dev_to_hda_codec(dev);
+ struct alc_spec *spec = cdc->spec;
+
+ hda_component_manager_unbind_acpi_notifications(cdc, &spec->comps, comp_acpi_device_notify);
+ hda_component_manager_unbind(cdc, &spec->comps);
}
-static void alc269_quanta_automute(struct hda_codec *codec)
+static const struct component_master_ops comp_master_ops = {
+ .bind = comp_bind,
+ .unbind = comp_unbind,
+};
+
+static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_codec *cdc,
+ struct snd_pcm_substream *sub, int action)
{
- snd_hda_gen_update_outputs(codec);
+ struct alc_spec *spec = cdc->spec;
- alc_write_coef_idx(codec, 0x0c, 0x680);
- alc_write_coef_idx(codec, 0x0c, 0x480);
+ hda_component_manager_playback_hook(&spec->comps, action);
}
-static void alc269_fixup_quanta_mute(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
+ const char *hid, const char *match_str, int count)
{
- struct alc_spec *spec = codec->spec;
- if (action != HDA_FIXUP_ACT_PROBE)
- return;
- spec->gen.automute_hook = alc269_quanta_automute;
+ struct alc_spec *spec = cdc->spec;
+ int ret;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ ret = hda_component_manager_init(cdc, &spec->comps, count, bus, hid,
+ match_str, &comp_master_ops);
+ if (ret)
+ return;
+
+ spec->gen.pcm_playback_hook = comp_generic_playback_hook;
+ break;
+ case HDA_FIXUP_ACT_FREE:
+ hda_component_manager_free(&spec->comps, &comp_master_ops);
+ break;
+ }
}
-static void alc269_x101_hp_automute_hook(struct hda_codec *codec,
- struct hda_jack_callback *jack)
+static void find_cirrus_companion_amps(struct hda_codec *cdc)
{
- struct alc_spec *spec = codec->spec;
- int vref;
- msleep(200);
- snd_hda_gen_hp_automute(codec, jack);
+ struct device *dev = hda_codec_dev(cdc);
+ struct acpi_device *adev;
+ struct fwnode_handle *fwnode __free(fwnode_handle) = NULL;
+ const char *bus = NULL;
+ static const struct {
+ const char *hid;
+ const char *name;
+ } acpi_ids[] = {{ "CSC3554", "cs35l54-hda" },
+ { "CSC3556", "cs35l56-hda" },
+ { "CSC3557", "cs35l57-hda" }};
+ char *match;
+ int i, count = 0, count_devindex = 0;
- vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
- msleep(100);
- snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- vref);
- msleep(500);
- snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- vref);
-}
+ for (i = 0; i < ARRAY_SIZE(acpi_ids); ++i) {
+ adev = acpi_dev_get_first_match_dev(acpi_ids[i].hid, NULL, -1);
+ if (adev)
+ break;
+ }
+ if (!adev) {
+ codec_dbg(cdc, "Did not find ACPI entry for a Cirrus Amp\n");
+ return;
+ }
-/*
- * Magic sequence to make Huawei Matebook X right speaker working (bko#197801)
- */
-struct hda_alc298_mbxinit {
- unsigned char value_0x23;
- unsigned char value_0x25;
-};
+ count = i2c_acpi_client_count(adev);
+ if (count > 0) {
+ bus = "i2c";
+ } else {
+ count = acpi_spi_count_resources(adev);
+ if (count > 0)
+ bus = "spi";
+ }
-static void alc298_huawei_mbx_stereo_seq(struct hda_codec *codec,
- const struct hda_alc298_mbxinit *initval,
- bool first)
-{
- snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x0);
- alc_write_coef_idx(codec, 0x26, 0xb000);
+ fwnode = fwnode_handle_get(acpi_fwnode_handle(adev));
+ acpi_dev_put(adev);
- if (first)
- snd_hda_codec_write(codec, 0x21, 0, AC_VERB_GET_PIN_SENSE, 0x0);
+ if (!bus) {
+ codec_err(cdc, "Did not find any buses for %s\n", acpi_ids[i].hid);
+ return;
+ }
- snd_hda_codec_write(codec, 0x6, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80);
- alc_write_coef_idx(codec, 0x26, 0xf000);
- alc_write_coef_idx(codec, 0x23, initval->value_0x23);
+ if (!fwnode) {
+ codec_err(cdc, "Could not get fwnode for %s\n", acpi_ids[i].hid);
+ return;
+ }
- if (initval->value_0x23 != 0x1e)
- alc_write_coef_idx(codec, 0x25, initval->value_0x25);
+ /*
+ * When available the cirrus,dev-index property is an accurate
+ * count of the amps in a system and is used in preference to
+ * the count of bus devices that can contain additional address
+ * alias entries.
+ */
+ count_devindex = fwnode_property_count_u32(fwnode, "cirrus,dev-index");
+ if (count_devindex > 0)
+ count = count_devindex;
- snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26);
- snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010);
+ match = devm_kasprintf(dev, GFP_KERNEL, "-%%s:00-%s.%%d", acpi_ids[i].name);
+ if (!match)
+ return;
+ codec_info(cdc, "Found %d %s on %s (%s)\n", count, acpi_ids[i].hid, bus, match);
+ comp_generic_fixup(cdc, HDA_FIXUP_ACT_PRE_PROBE, bus, acpi_ids[i].hid, match, count);
}
-static void alc298_fixup_huawei_mbx_stereo(struct hda_codec *codec,
- const struct hda_fixup *fix,
- int action)
+static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
- /* Initialization magic */
- static const struct hda_alc298_mbxinit dac_init[] = {
- {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
- {0x10, 0x00}, {0x1a, 0x40}, {0x1b, 0x82}, {0x1c, 0x00},
- {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
- {0x20, 0xc2}, {0x21, 0xc8}, {0x22, 0x26}, {0x23, 0x24},
- {0x27, 0xff}, {0x28, 0xff}, {0x29, 0xff}, {0x2a, 0x8f},
- {0x2b, 0x02}, {0x2c, 0x48}, {0x2d, 0x34}, {0x2e, 0x00},
- {0x2f, 0x00},
- {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
- {0x34, 0x00}, {0x35, 0x01}, {0x36, 0x93}, {0x37, 0x0c},
- {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0xf8}, {0x38, 0x80},
- {}
- };
- const struct hda_alc298_mbxinit *seq;
+ comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
+}
- if (action != HDA_FIXUP_ACT_INIT)
- return;
+static void cs35l41_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
+}
- /* Start */
- snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x00);
- snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80);
- alc_write_coef_idx(codec, 0x26, 0xf000);
- alc_write_coef_idx(codec, 0x22, 0x31);
- alc_write_coef_idx(codec, 0x23, 0x0b);
- alc_write_coef_idx(codec, 0x25, 0x00);
- snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26);
- snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010);
+static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
+}
- for (seq = dac_init; seq->value_0x23; seq++)
- alc298_huawei_mbx_stereo_seq(codec, seq, seq == dac_init);
+static void cs35l41_fixup_spi_one(struct hda_codec *codec, const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 1);
}
-static void alc269_fixup_x101_headset_mic(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action)
{
- struct alc_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
- spec->gen.hp_automute_hook = alc269_x101_hp_automute_hook;
- }
+ comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
}
-static void alc_update_vref_led(struct hda_codec *codec, hda_nid_t pin,
- bool polarity, bool on)
+static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
+ int action)
{
- unsigned int pinval;
+ comp_generic_fixup(cdc, action, "i2c", "CLSA0100", "-%s:00-cs35l41-hda.%d", 2);
+}
- if (!pin)
- return;
- if (polarity)
- on = !on;
- pinval = snd_hda_codec_get_pin_target(codec, pin);
- pinval &= ~AC_PINCTL_VREFEN;
- pinval |= on ? AC_PINCTL_VREF_80 : AC_PINCTL_VREF_HIZ;
- /* temporarily power up/down for setting VREF */
- snd_hda_power_up_pm(codec);
- snd_hda_set_pin_ctl_cache(codec, pin, pinval);
- snd_hda_power_down_pm(codec);
-}
-
-/* update mute-LED according to the speaker mute state via mic VREF pin */
-static int vref_mute_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
- struct alc_spec *spec = codec->spec;
-
- alc_update_vref_led(codec, spec->mute_led_nid,
- spec->mute_led_polarity, brightness);
- return 0;
-}
-
-/* Make sure the led works even in runtime suspend */
-static unsigned int led_power_filter(struct hda_codec *codec,
- hda_nid_t nid,
- unsigned int power_state)
+static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
+ int action)
{
- struct alc_spec *spec = codec->spec;
-
- if (power_state != AC_PWRST_D3 || nid == 0 ||
- (nid != spec->mute_led_nid && nid != spec->cap_mute_led_nid))
- return power_state;
-
- /* Set pin ctl again, it might have just been set to 0 */
- snd_hda_set_pin_ctl(codec, nid,
- snd_hda_codec_get_pin_target(codec, nid));
-
- return snd_hda_gen_path_power_filter(codec, nid, power_state);
+ comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2);
}
-static void alc269_fixup_hp_mute_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void alc285_fixup_asus_ga403u(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
- struct alc_spec *spec = codec->spec;
- const struct dmi_device *dev = NULL;
-
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
- return;
-
- while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
- int pol, pin;
- if (sscanf(dev->name, "HP_Mute_LED_%d_%x", &pol, &pin) != 2)
- continue;
- if (pin < 0x0a || pin >= 0x10)
- break;
- spec->mute_led_polarity = pol;
- spec->mute_led_nid = pin - 0x0a + 0x18;
- snd_hda_gen_add_mute_led_cdev(codec, vref_mute_led_set);
- codec->power_filter = led_power_filter;
- codec_dbg(codec,
- "Detected mute LED for %x:%d\n", spec->mute_led_nid,
- spec->mute_led_polarity);
- break;
- }
+ /*
+ * The same SSID has been re-used in different hardware, they have
+ * different codecs and the newer GA403U has a ALC285.
+ */
+ if (cdc->core.vendor_id != 0x10ec0285)
+ alc_fixup_inv_dmic(cdc, fix, action);
}
-static void alc269_fixup_hp_mute_led_micx(struct hda_codec *codec,
- const struct hda_fixup *fix,
- int action, hda_nid_t pin)
+static void tas2781_fixup_tias_i2c(struct hda_codec *cdc,
+ const struct hda_fixup *fix, int action)
{
- struct alc_spec *spec = codec->spec;
-
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->mute_led_polarity = 0;
- spec->mute_led_nid = pin;
- snd_hda_gen_add_mute_led_cdev(codec, vref_mute_led_set);
- codec->power_filter = led_power_filter;
- }
+ comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1);
}
-static void alc269_fixup_hp_mute_led_mic1(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void tas2781_fixup_spi(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
- alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x18);
+ comp_generic_fixup(cdc, action, "spi", "TXNW2781", "-%s:00-tas2781-hda.%d", 2);
}
-static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void tas2781_fixup_txnw_i2c(struct hda_codec *cdc,
+ const struct hda_fixup *fix, int action)
{
- alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x19);
+ comp_generic_fixup(cdc, action, "i2c", "TXNW2781", "-%s:00-tas2781-hda.%d", 1);
}
-static void alc269_fixup_hp_mute_led_mic3(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
+ const struct hda_fixup *fix, int action)
{
- alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1b);
+ comp_generic_fixup(cdc, action, "i2c", "INT8866", "-%s:00", 1);
}
-/* update LED status via GPIO */
-static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
- int polarity, bool enabled)
+static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
{
- if (polarity)
- enabled = !enabled;
- alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
+ alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
}
-/* turn on/off mute LED via GPIO per vmaster hook */
-static int gpio_mute_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
- struct alc_spec *spec = codec->spec;
- alc_update_gpio_led(codec, spec->gpio_mute_led_mask,
- spec->mute_led_polarity, !brightness);
- return 0;
-}
+/* for alc295_fixup_hp_top_speakers */
+#include "../helpers/hp_x360.c"
-/* turn on/off mic-mute LED via GPIO per capture hook */
-static int micmute_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
- struct alc_spec *spec = codec->spec;
+/* for alc285_fixup_ideapad_s740_coef() */
+#include "../helpers/ideapad_s740.c"
- alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
- spec->micmute_led_polarity, !brightness);
- return 0;
-}
+static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
+ WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
+ WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x29, 0x3000),
+ WRITE_COEF(0x37, 0xfe05), WRITE_COEF(0x45, 0x5089),
+ {}
+};
-/* setup mute and mic-mute GPIO bits, add hooks appropriately */
-static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
- int action,
- unsigned int mute_mask,
- unsigned int micmute_mask)
+static void alc256_fixup_set_coef_defaults(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
{
- struct alc_spec *spec = codec->spec;
-
- alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
-
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
- return;
- if (mute_mask) {
- spec->gpio_mute_led_mask = mute_mask;
- snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set);
- }
- if (micmute_mask) {
- spec->gpio_mic_led_mask = micmute_mask;
- snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set);
- }
+ /*
+ * A certain other OS sets these coeffs to different values. On at least
+ * one TongFang barebone these settings might survive even a cold
+ * reboot. So to restore a clean slate the values are explicitly reset
+ * to default here. Without this, the external microphone is always in a
+ * plugged-in state, while the internal microphone is always in an
+ * unplugged state, breaking the ability to use the internal microphone.
+ */
+ alc_process_coef_fw(codec, alc256_fixup_set_coef_defaults_coefs);
}
-static void alc236_fixup_hp_gpio_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- alc_fixup_hp_gpio_led(codec, action, 0x02, 0x01);
-}
+static const struct coef_fw alc233_fixup_no_audio_jack_coefs[] = {
+ WRITE_COEF(0x1a, 0x9003), WRITE_COEF(0x1b, 0x0e2b), WRITE_COEF(0x37, 0xfe06),
+ WRITE_COEF(0x38, 0x4981), WRITE_COEF(0x45, 0xd489), WRITE_COEF(0x46, 0x0074),
+ WRITE_COEF(0x49, 0x0149),
+ {}
+};
-static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void alc233_fixup_no_audio_jack(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
{
- alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
+ /*
+ * The audio jack input and output is not detected on the ASRock NUC Box
+ * 1100 series when cold booting without this fix. Warm rebooting from a
+ * certain other OS makes the audio functional, as COEF settings are
+ * preserved in this case. This fix sets these altered COEF values as
+ * the default.
+ */
+ alc_process_coef_fw(codec, alc233_fixup_no_audio_jack_coefs);
}
-static void alc285_fixup_hp_gpio_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
{
- alc_fixup_hp_gpio_led(codec, action, 0x04, 0x01);
+ /*
+ * The Clevo NJ51CU comes either with the ALC293 or the ALC256 codec,
+ * but uses the 0x8686 subproduct id in both cases. The ALC256 codec
+ * needs an additional quirk for sound working after suspend and resume.
+ */
+ if (codec->core.vendor_id == 0x10ec0256) {
+ alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+ snd_hda_codec_set_pincfg(codec, 0x19, 0x04a11120);
+ } else {
+ snd_hda_codec_set_pincfg(codec, 0x1a, 0x04a1113c);
+ }
}
-static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void alc256_decrease_headphone_amp_val(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
{
- alc_fixup_hp_gpio_led(codec, action, 0x02, 0x20);
-}
+ u32 caps;
+ u8 nsteps, offs;
-static void alc287_fixup_hp_gpio_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- alc_fixup_hp_gpio_led(codec, action, 0x10, 0);
-}
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
-static void alc245_fixup_hp_gpio_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
+ caps = query_amp_caps(codec, 0x3, HDA_OUTPUT);
+ nsteps = ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) - 10;
+ offs = ((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT) - 10;
+ caps &= ~AC_AMPCAP_NUM_STEPS & ~AC_AMPCAP_OFFSET;
+ caps |= (nsteps << AC_AMPCAP_NUM_STEPS_SHIFT) | (offs << AC_AMPCAP_OFFSET_SHIFT);
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
- spec->micmute_led_polarity = 1;
- alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
+ if (snd_hda_override_amp_caps(codec, 0x3, HDA_OUTPUT, caps))
+ codec_warn(codec, "failed to override amp caps for NID 0x3\n");
}
-/* turn on/off mic-mute LED per capture hook via VREF change */
-static int vref_micmute_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+static void alc_fixup_dell4_mic_no_presence_quiet(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
{
- struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
struct alc_spec *spec = codec->spec;
+ struct hda_input_mux *imux = &spec->gen.input_mux;
+ int i;
- alc_update_vref_led(codec, spec->cap_mute_led_nid,
- spec->micmute_led_polarity, brightness);
- return 0;
+ alc269_fixup_limit_int_mic_boost(codec, fix, action);
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ /**
+ * Set the vref of pin 0x19 (Headset Mic) and pin 0x1b (Headphone Mic)
+ * to Hi-Z to avoid pop noises at startup and when plugging and
+ * unplugging headphones.
+ */
+ snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
+ snd_hda_codec_set_pin_target(codec, 0x1b, PIN_VREFHIZ);
+ break;
+ case HDA_FIXUP_ACT_PROBE:
+ /**
+ * Make the internal mic (0x12) the default input source to
+ * prevent pop noises on cold boot.
+ */
+ for (i = 0; i < imux->num_items; i++) {
+ if (spec->gen.imux_pins[i] == 0x12) {
+ spec->gen.cur_mux[0] = i;
+ break;
+ }
+ }
+ break;
+ }
}
-static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void alc287_fixup_yoga9_14iap7_bass_spk_pin(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
{
- struct alc_spec *spec = codec->spec;
-
- alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- /* Like hp_gpio_mic1_led, but also needs GPIO4 low to
- * enable headphone amp
- */
- spec->gpio_mask |= 0x10;
- spec->gpio_dir |= 0x10;
- spec->cap_mute_led_nid = 0x18;
- snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set);
- codec->power_filter = led_power_filter;
+ /*
+ * The Pin Complex 0x17 for the bass speakers is wrongly reported as
+ * unconnected.
+ */
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x17, 0x90170121 },
+ { }
+ };
+ /*
+ * Avoid DAC 0x06 and 0x08, as they have no volume controls.
+ * DAC 0x02 and 0x03 would be fine.
+ */
+ static const hda_nid_t conn[] = { 0x02, 0x03 };
+ /*
+ * Prefer both speakerbar (0x14) and bass speakers (0x17) connected to DAC 0x02.
+ * Headphones (0x21) are connected to DAC 0x03.
+ */
+ static const hda_nid_t preferred_pairs[] = {
+ 0x14, 0x02,
+ 0x17, 0x02,
+ 0x21, 0x03,
+ 0
+ };
+ struct alc_spec *spec = codec->spec;
+
++ /* Support Audio mute LED and Mic mute LED on keyboard */
++ hda_fixup_ideapad_acpi(codec, fix, action);
++
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ spec->gen.preferred_dacs = preferred_pairs;
+ break;
}
}