From: Takashi Iwai Date: Mon, 14 Jul 2025 12:29:49 +0000 (+0200) Subject: Merge branch 'for-linus' into for-next X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=891667cefd16e71cd847c75dbdc272acd996bb68;p=thirdparty%2Fkernel%2Flinux.git Merge branch 'for-linus' into for-next Signed-off-by: Takashi Iwai --- 891667cefd16e71cd847c75dbdc272acd996bb68 diff --cc sound/hda/codecs/realtek/alc269.c index 03daa58a88de6,47ceb6f322912..5b899e1371595 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@@ -2826,376 -4195,402 +2826,379 @@@ static void alc287_fixup_legion_15imhg0 { 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; } }