[alsa-devel] [PATCH 0/5] ALSA: hda - second batch for mute LED helper & cleanups
Hi,
this is the additional changes for applying the common mute LED helper to more codecs and machines, to be applied on top of the previous two patches ("[PATCH 1/2] ALSA: hda - Move mic mute LED helper to the generic parser" and "[PATCH 2/2] ALSA: hda - Use the common helper for thinkpad_acpi mic mute LED handling"). Now HP laptops on Realtek and Conexant, as well as on IDT codecs receive the same mute LED functionality.
Takashi
===
Takashi Iwai (5): ALSA: hda/realtek - Use the mic-mute LED helper for HP and others ALSA: hda/conexant - Use the mic-mute LED helper ALSA: hda - Allow multiple ADCs for mic mute LED controls ALSA: hda/sigmatel - Use common helper for mic mute LED ALSA: hda - Sanity check of unexpected cap_sync_hook override
sound/pci/hda/hda_generic.c | 32 ++++++++++------------ sound/pci/hda/patch_conexant.c | 13 ++++----- sound/pci/hda/patch_realtek.c | 50 +++++++++++++--------------------- sound/pci/hda/patch_sigmatel.c | 31 ++++----------------- 4 files changed, 44 insertions(+), 82 deletions(-)
Similar as the previous commit, convert to use the common helper for controlling the mic mute LED for HP and other machines in the Realtek codec driver, too. This will give the mic mute LED enum as gratis.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/patch_realtek.c | 49 +++++++++++++---------------------- 1 file changed, 18 insertions(+), 31 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 487ceb9fd038..32a7a72033ae 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3718,16 +3718,12 @@ static void alc_fixup_gpio_mute_hook(void *private_data, int enabled) }
/* turn on/off mic-mute LED via GPIO per capture hook */ -static void alc_fixup_gpio_mic_mute_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc_gpio_micmute_update(struct hda_codec *codec) { struct alc_spec *spec = codec->spec;
- if (ucontrol) - alc_update_gpio_led(codec, spec->gpio_mic_led_mask, - ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]); + alc_update_gpio_led(codec, spec->gpio_mic_led_mask, + spec->gen.micmute_led.led_value); }
static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, @@ -3742,12 +3738,12 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; spec->gpio_led = 0; spec->mute_led_polarity = 0; spec->gpio_mute_led_mask = 0x08; spec->gpio_mic_led_mask = 0x10; snd_hda_add_verbs(codec, gpio_init); + snd_hda_gen_add_micmute_led(codec, alc_gpio_micmute_update); } }
@@ -3763,39 +3759,30 @@ static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; spec->gpio_led = 0; spec->mute_led_polarity = 0; spec->gpio_mute_led_mask = 0x02; spec->gpio_mic_led_mask = 0x20; snd_hda_add_verbs(codec, gpio_init); + snd_hda_gen_add_micmute_led(codec, alc_gpio_micmute_update); } }
/* turn on/off mic-mute LED per capture hook */ -static void alc269_fixup_hp_cap_mic_mute_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc_cap_micmute_update(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int pinval, enable, disable; + unsigned int pinval;
+ if (!spec->cap_mute_led_nid) + return; pinval = snd_hda_codec_get_pin_target(codec, spec->cap_mute_led_nid); pinval &= ~AC_PINCTL_VREFEN; - enable = pinval | AC_PINCTL_VREF_80; - disable = pinval | AC_PINCTL_VREF_HIZ; - - if (!ucontrol) - return; - - if (ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]) - pinval = disable; + if (spec->gen.micmute_led.led_value) + pinval |= AC_PINCTL_VREF_80; else - pinval = enable; - - if (spec->cap_mute_led_nid) - snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval); + pinval |= AC_PINCTL_VREF_HIZ; + snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval); }
static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec, @@ -3810,12 +3797,12 @@ static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; spec->gpio_led = 0; spec->mute_led_polarity = 0; spec->gpio_mute_led_mask = 0x08; spec->cap_mute_led_nid = 0x18; snd_hda_add_verbs(codec, gpio_init); + snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update); codec->power_filter = led_power_filter; } } @@ -3833,12 +3820,12 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; spec->gpio_led = 0; spec->mute_led_polarity = 0; spec->gpio_mute_led_mask = 0x08; spec->cap_mute_led_nid = 0x18; snd_hda_add_verbs(codec, gpio_init); + snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update); codec->power_filter = led_power_filter; } } @@ -3915,11 +3902,11 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, gpio2_mic_hotkey_event);
spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; spec->gpio_led = 0; spec->mute_led_polarity = 0; spec->gpio_mute_led_mask = 0x08; spec->gpio_mic_led_mask = 0x10; + snd_hda_gen_add_micmute_led(codec, alc_gpio_micmute_update); return; }
@@ -3957,10 +3944,10 @@ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec, snd_hda_jack_detect_enable_callback(codec, 0x1b, gpio2_mic_hotkey_event);
- spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; spec->gpio_led = 0; spec->mute_led_polarity = 0; spec->gpio_mic_led_mask = 0x04; + snd_hda_gen_add_micmute_led(codec, alc_gpio_micmute_update); return; }
@@ -3988,10 +3975,10 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; - spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; spec->mute_led_polarity = 0; spec->mute_led_nid = 0x1a; spec->cap_mute_led_nid = 0x18; + snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update); spec->gen.vmaster_mute_enum = 1; codec->power_filter = led_power_filter; }
Convert to use the common helper for controlling the mic mute LED for HP laptops, just as we've done for Realtek codecs. This will give the mic mute LED enum as gratis.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/patch_conexant.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e7fcfc3b8885..a9fd0572d526 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -695,16 +695,12 @@ static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled) }
/* turn on/off mic-mute LED via GPIO per capture hook */ -static void cxt_fixup_gpio_mic_mute_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void cxt_gpio_micmute_update(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec;
- if (ucontrol) - cxt_update_gpio_led(codec, spec->gpio_mic_led_mask, - ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]); + cxt_update_gpio_led(codec, spec->gpio_mic_led_mask, + spec->gen.micmute_led.led_value); }
@@ -721,11 +717,11 @@ static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook; - spec->gen.cap_sync_hook = cxt_fixup_gpio_mic_mute_hook; spec->gpio_led = 0; spec->mute_led_polarity = 0; spec->gpio_mute_led_mask = 0x01; spec->gpio_mic_led_mask = 0x02; + snd_hda_gen_add_micmute_led(codec, cxt_gpio_micmute_update); } snd_hda_add_verbs(codec, gpio_init); if (spec->gpio_led)
Instead of refusing, allow the configuration with the multiple ADCs (thus multiple capture switches) for enabling the mic mute LED. This has been done for Sigmatel/IDT codecs, and we treat the OR-ed values from all capture switches as the boolean condition.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_generic.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-)
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index cdce9ce6b901..942f96e184b6 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3922,7 +3922,7 @@ static void call_micmute_led_update(struct hda_codec *codec) val = 0; break; case MICMUTE_LED_FOLLOW_CAPTURE: - val = spec->micmute_led.capture; + val = !!spec->micmute_led.capture; break; case MICMUTE_LED_FOLLOW_MUTE: default: @@ -3942,17 +3942,21 @@ static void update_micmute_led(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol) { struct hda_gen_spec *spec = codec->spec; + unsigned int mask;
if (spec->micmute_led.old_hook) spec->micmute_led.old_hook(codec, kcontrol, ucontrol);
if (!ucontrol) return; - if (!strcmp("Capture Switch", ucontrol->id.name) && - !ucontrol->id.index) { + mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + if (!strcmp("Capture Switch", ucontrol->id.name)) { /* TODO: How do I verify if it's a mono or stereo here? */ - spec->micmute_led.capture = (ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]); + if (ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]) + spec->micmute_led.capture |= mask; + else + spec->micmute_led.capture &= ~mask; call_micmute_led_update(codec); } } @@ -4008,25 +4012,17 @@ static const struct snd_kcontrol_new micmute_led_mode_ctl = { * @hook: the callback for updating LED * * Called from the codec drivers for offering the mic mute LED controls. - * Only valid for a single ADC (or a single input). When established, it - * sets up cap_sync_hook and triggers the callback at each time when the - * capture mixer switch changes. The callback is supposed to update the LED - * accordingly. + * When established, it sets up cap_sync_hook and triggers the callback at + * each time when the capture mixer switch changes. The callback is supposed + * to update the LED accordingly. * - * Returns 1 if the hook is established, 0 if skipped (no valid config), or - * a negative error code. + * Returns 0 if the hook is established or a negative error code. */ int snd_hda_gen_add_micmute_led(struct hda_codec *codec, void (*hook)(struct hda_codec *)) { struct hda_gen_spec *spec = codec->spec;
- if (spec->num_adc_nids > 1 && !spec->dyn_adc_switch) { - codec_dbg(codec, - "Skipping micmute LED control due to several ADCs"); - return 0; - } - spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE; spec->micmute_led.capture = 0; spec->micmute_led.led_value = 0; @@ -4035,7 +4031,7 @@ int snd_hda_gen_add_micmute_led(struct hda_codec *codec, spec->cap_sync_hook = update_micmute_led; if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl)) return -ENOMEM; - return 1; + return 0; } EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led);
To simplify the code and to get the mic-mute LED behavior control, use the new helper function for controlling the mic mute LED instead of open-codes.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/patch_sigmatel.c | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-)
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 63d15b545b33..046705b4691a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -332,33 +332,15 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, }
/* hook for controlling mic-mute LED GPIO */ -static void stac_capture_led_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void stac_capture_led_update(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - unsigned int mask; - bool cur_mute, prev_mute;
- if (!kcontrol || !ucontrol) - return; - - mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - prev_mute = !spec->mic_enabled; - if (ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]) - spec->mic_enabled |= mask; + if (spec->gen.micmute_led.led_value) + spec->gpio_data |= spec->mic_mute_led_gpio; else - spec->mic_enabled &= ~mask; - cur_mute = !spec->mic_enabled; - if (cur_mute != prev_mute) { - if (cur_mute) - spec->gpio_data |= spec->mic_mute_led_gpio; - else - spec->gpio_data &= ~spec->mic_mute_led_gpio; - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data); - } + spec->gpio_data &= ~spec->mic_mute_led_gpio; + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); }
static int stac_vrefout_set(struct hda_codec *codec, @@ -4656,8 +4638,7 @@ static void stac_setup_gpio(struct hda_codec *codec) spec->gpio_dir |= spec->mic_mute_led_gpio; spec->mic_enabled = 0; spec->gpio_data |= spec->mic_mute_led_gpio; - - spec->gen.cap_sync_hook = stac_capture_led_hook; + snd_hda_gen_add_micmute_led(codec, stac_capture_led_update); } }
There are a couple of places setting cap_sync_hook in the codec drivers, and they just overwrite the value. Add a sanity check via WARN_ON() in case if an old non-NULL value is overridden and forgotten.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/patch_conexant.c | 1 + sound/pci/hda/patch_realtek.c | 1 + 2 files changed, 2 insertions(+)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index a9fd0572d526..b7339cb5c45b 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -343,6 +343,7 @@ static void cxt_fixup_headphone_mic(struct hda_codec *codec, snd_hdac_regmap_add_vendor_verb(&codec->core, 0x410); break; case HDA_FIXUP_ACT_PROBE: + WARN_ON(spec->gen.cap_sync_hook); spec->gen.cap_sync_hook = cxt_update_headset_mode_hook; spec->gen.automute_hook = cxt_update_headset_mode; break; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 32a7a72033ae..d9461eebcfdf 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4828,6 +4828,7 @@ static void alc_probe_headset_mode(struct hda_codec *codec) spec->headphone_mic_pin = cfg->inputs[i].pin; }
+ WARN_ON(spec->gen.cap_sync_hook); spec->gen.cap_sync_hook = alc_update_headset_mode_hook; spec->gen.automute_hook = alc_update_headset_mode; spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
participants (1)
-
Takashi Iwai