There is a headset jack plugging indicator led on the LENOVO P520 front panel, we expect this led to be on if we plug a headphone or headset in that jack, and expect this led to be off if there is nothing plugged in that jack. After adding the JACKPLUG led in the ledtrig_audio.c, we could add led control in the hda audio driver via ledtrig API. On the LENOVO P520, the jack indicator led connects to the alc233 gpio2, we hook a callback in the unsol event handler to update this led. Signed-off-by: Hui Wang <hui.wang@xxxxxxxxxxxxx> --- sound/pci/hda/hda_generic.c | 26 ++++++++++++++++++++++ sound/pci/hda/hda_generic.h | 3 +++ sound/pci/hda/patch_realtek.c | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index bbb17481159e..6b4b06583e98 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3888,6 +3888,32 @@ static int parse_mic_boost(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_GENERIC_LEDS +/** + * snd_dha_gen_add_jackplug_led_cdev - Create a LED classdev and enable as jack plugging LED + * @codec: the HDA codec + * @callback: the callback for LED classdev brightness_set_blocking + */ +int snd_hda_gen_add_jackplug_led_cdev(struct hda_codec *codec, + int (*callback)(struct led_classdev *, + enum led_brightness)) +{ + struct led_classdev *cdev; + + cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->name = "hda::jackplug"; + cdev->max_brightness = 1; + cdev->default_trigger = "audio-jackplug"; + cdev->brightness_set_blocking = callback; + cdev->brightness = ledtrig_audio_get(LED_AUDIO_JACKPLUG); + cdev->flags = LED_CORE_SUSPENDRESUME; + + return devm_led_classdev_register(&codec->core.dev, cdev); +} +EXPORT_SYMBOL_GPL(snd_hda_gen_add_jackplug_led_cdev); + /* * vmaster mute LED hook helpers */ diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index a43f0bb77dae..8d363d14d0c3 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -360,5 +360,8 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec, int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec, int (*callback)(struct led_classdev *, enum led_brightness)); +int snd_hda_gen_add_jackplug_led_cdev(struct hda_codec *codec, + int (*callback)(struct led_classdev *, + enum led_brightness)); #endif /* __SOUND_HDA_GENERIC_H */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b6dc47da1d7b..8dbc7ef76206 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -90,11 +90,13 @@ struct alc_spec { /* mute LED for HP laptops, see vref_mute_led_set() */ int mute_led_polarity; int micmute_led_polarity; + int jackplug_led_polarity; hda_nid_t mute_led_nid; hda_nid_t cap_mute_led_nid; unsigned int gpio_mute_led_mask; unsigned int gpio_mic_led_mask; + unsigned int gpio_jackplug_led_mask; struct alc_coef_led mute_led_coef; struct alc_coef_led mic_led_coef; @@ -5905,15 +5907,50 @@ static void alc285_fixup_thinkpad_x1_gen7(struct hda_codec *codec, } } +/* turn on/off jackplugging indicator LED via GPIO per unsol event callback */ +static int gpio_jackplug_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_jackplug_led_mask, + spec->jackplug_led_polarity, !brightness); + return 0; +} + +static void alc_update_hp_jack_stat_led(struct hda_codec *codec, + struct hda_jack_callback *cb) +{ + u32 pin_sense; + + pin_sense = snd_hda_jack_pin_sense(codec, 0x21, 0); + ledtrig_audio_set(LED_AUDIO_JACKPLUG, + (pin_sense & AC_PINSENSE_PRESENCE) ? LED_ON : LED_OFF); +} + static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec, const struct hda_fixup *fix, int action) { + struct alc_spec *spec = codec->spec; alc_fixup_dual_codecs(codec, fix, action); switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: /* override card longname to provide a unique UCM profile */ strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs"); + + /* the jack plug indicator led connects to gpio2 of alc233 */ + if (codec->core.vendor_id == 0x10ec0662) + break; + /* enable gpio2 and set it to output */ + spec->gpio_mask |= 0x2; + spec->gpio_dir |= 0x2; + alc_write_gpio(codec); + spec->gpio_jackplug_led_mask = 0x2; + spec->jackplug_led_polarity = 0x0; + snd_hda_gen_add_jackplug_led_cdev(codec, gpio_jackplug_led_set); + break; case HDA_FIXUP_ACT_BUILD: /* rename Capture controls depending on the codec */ @@ -5925,6 +5962,11 @@ static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec, codec->addr == 0 ? "Rear-Panel Capture Switch" : "Front-Panel Capture Switch"); + + if (codec->core.vendor_id == 0x10ec0662) + break; + alc_update_hp_jack_stat_led(codec, NULL); + snd_hda_jack_detect_enable_callback(codec, 0x21, alc_update_hp_jack_stat_led); break; } } -- 2.17.1