platform/x86: dell-laptop: Register ctl-led for speaker-mute
authorKoba Ko <koba.ko@canonical.com>
Wed, 8 Mar 2023 06:24:14 +0000 (14:24 +0800)
committerHans de Goede <hdegoede@redhat.com>
Thu, 16 Mar 2023 13:51:07 +0000 (14:51 +0100)
Some platforms have the speaker-mute led and
current driver doesn't control it.

If the platform support the control of speaker-mute led, register it

Signed-off-by: Koba Ko <koba.ko@canonical.com>
Link: https://lore.kernel.org/r/20230308062414.1048913-1-koba.ko@canonical.com
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
drivers/platform/x86/dell/dell-laptop.c
drivers/platform/x86/dell/dell-smbios.h

index e92c3ad06d6965499d2965fc9a114e86c49b9524..6586438356de76fbab93cd88d85ef6c88574d852 100644 (file)
@@ -97,6 +97,7 @@ static struct rfkill *bluetooth_rfkill;
 static struct rfkill *wwan_rfkill;
 static bool force_rfkill;
 static bool micmute_led_registered;
+static bool mute_led_registered;
 
 module_param(force_rfkill, bool, 0444);
 MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models");
@@ -2177,6 +2178,34 @@ static struct led_classdev micmute_led_cdev = {
        .default_trigger = "audio-micmute",
 };
 
+static int mute_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness brightness)
+{
+       struct calling_interface_buffer buffer;
+       struct calling_interface_token *token;
+       int state = brightness != LED_OFF;
+
+       if (state == 0)
+               token = dell_smbios_find_token(GLOBAL_MUTE_DISABLE);
+       else
+               token = dell_smbios_find_token(GLOBAL_MUTE_ENABLE);
+
+       if (!token)
+               return -ENODEV;
+
+       dell_fill_request(&buffer, token->location, token->value, 0, 0);
+       dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
+
+       return 0;
+}
+
+static struct led_classdev mute_led_cdev = {
+       .name = "platform::mute",
+       .max_brightness = 1,
+       .brightness_set_blocking = mute_led_set,
+       .default_trigger = "audio-mute",
+};
+
 static int __init dell_init(void)
 {
        struct calling_interface_token *token;
@@ -2230,6 +2259,15 @@ static int __init dell_init(void)
                micmute_led_registered = true;
        }
 
+       if (dell_smbios_find_token(GLOBAL_MUTE_DISABLE) &&
+           dell_smbios_find_token(GLOBAL_MUTE_ENABLE)) {
+               mute_led_cdev.brightness = ledtrig_audio_get(LED_AUDIO_MUTE);
+               ret = led_classdev_register(&platform_device->dev, &mute_led_cdev);
+               if (ret < 0)
+                       goto fail_backlight;
+               mute_led_registered = true;
+       }
+
        if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                return 0;
 
@@ -2277,6 +2315,8 @@ fail_get_brightness:
 fail_backlight:
        if (micmute_led_registered)
                led_classdev_unregister(&micmute_led_cdev);
+       if (mute_led_registered)
+               led_classdev_unregister(&mute_led_cdev);
 fail_led:
        dell_cleanup_rfkill();
 fail_rfkill:
@@ -2299,6 +2339,8 @@ static void __exit dell_exit(void)
        backlight_device_unregister(dell_backlight_device);
        if (micmute_led_registered)
                led_classdev_unregister(&micmute_led_cdev);
+       if (mute_led_registered)
+               led_classdev_unregister(&mute_led_cdev);
        dell_cleanup_rfkill();
        if (platform_device) {
                platform_device_unregister(platform_device);
index 75fa8ea0476dc555b6136825ab6cf9b7a7d61b4e..eb341bf000c675e8cf2d3860a4d35c6bf7d49cd4 100644 (file)
@@ -34,6 +34,8 @@
 #define KBD_LED_AUTO_100_TOKEN 0x02F6
 #define GLOBAL_MIC_MUTE_ENABLE 0x0364
 #define GLOBAL_MIC_MUTE_DISABLE        0x0365
+#define GLOBAL_MUTE_ENABLE     0x058C
+#define GLOBAL_MUTE_DISABLE    0x058D
 
 struct notifier_block;