]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/platform/x86/fujitsu-laptop.c
platform/x86: fujitsu-laptop: switch to managed LED class devices
[mirror_ubuntu-bionic-kernel.git] / drivers / platform / x86 / fujitsu-laptop.c
index 5e3e9511caaffefd10c13d36362006454e73c15a..c3e8df425e23be2c421915d41f290b49cfe29175 100644 (file)
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
 #include <linux/kfifo.h>
+#include <linux/leds.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#if IS_ENABLED(CONFIG_LEDS_CLASS)
-#include <linux/leds.h>
-#endif
 #include <acpi/video.h>
 
 #define FUJITSU_DRIVER_VERSION "0.6.0"
@@ -94,7 +92,6 @@
 #define FLAG_LID       0x100
 #define FLAG_DOCK      0x200
 
-#if IS_ENABLED(CONFIG_LEDS_CLASS)
 /* FUNC interface - LED control */
 #define FUNC_LED_OFF   0x1
 #define FUNC_LED_ON    0x30001
 #define RADIO_LED_ON   0x20
 #define ECO_LED        0x10000
 #define ECO_LED_ON     0x80000
-#endif
 
 /* Hotkey details */
 #define KEY1_CODE      0x410   /* codes for the keys in the GIRB register */
 /* Device controlling the backlight and associated keys */
 struct fujitsu_bl {
        acpi_handle acpi_handle;
-       struct acpi_device *dev;
        struct input_dev *input;
        char phys[32];
        struct backlight_device *bl_device;
-
        unsigned int max_brightness;
-       unsigned int brightness_changed;
        unsigned int brightness_level;
 };
 
 static struct fujitsu_bl *fujitsu_bl;
 static int use_alt_lcd_levels = -1;
-static int disable_brightness_adjust = -1;
+static bool disable_brightness_adjust;
 
 /* Device used to access hotkeys and other features on the laptop */
 struct fujitsu_laptop {
@@ -160,57 +153,10 @@ struct fujitsu_laptop {
        spinlock_t fifo_lock;
        int flags_supported;
        int flags_state;
-       int logolamp_registered;
-       int kblamps_registered;
-       int radio_led_registered;
-       int eco_led_registered;
 };
 
 static struct fujitsu_laptop *fujitsu_laptop;
 
-#if IS_ENABLED(CONFIG_LEDS_CLASS)
-static enum led_brightness logolamp_get(struct led_classdev *cdev);
-static int logolamp_set(struct led_classdev *cdev,
-                              enum led_brightness brightness);
-
-static struct led_classdev logolamp_led = {
- .name = "fujitsu::logolamp",
- .brightness_get = logolamp_get,
- .brightness_set_blocking = logolamp_set
-};
-
-static enum led_brightness kblamps_get(struct led_classdev *cdev);
-static int kblamps_set(struct led_classdev *cdev,
-                              enum led_brightness brightness);
-
-static struct led_classdev kblamps_led = {
- .name = "fujitsu::kblamps",
- .brightness_get = kblamps_get,
- .brightness_set_blocking = kblamps_set
-};
-
-static enum led_brightness radio_led_get(struct led_classdev *cdev);
-static int radio_led_set(struct led_classdev *cdev,
-                              enum led_brightness brightness);
-
-static struct led_classdev radio_led = {
- .name = "fujitsu::radio_led",
- .default_trigger = "rfkill-any",
- .brightness_get = radio_led_get,
- .brightness_set_blocking = radio_led_set
-};
-
-static enum led_brightness eco_led_get(struct led_classdev *cdev);
-static int eco_led_set(struct led_classdev *cdev,
-                              enum led_brightness brightness);
-
-static struct led_classdev eco_led = {
- .name = "fujitsu::eco_led",
- .brightness_get = eco_led_get,
- .brightness_set_blocking = eco_led_set
-};
-#endif
-
 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
 static u32 dbg_level = 0x03;
 #endif
@@ -241,151 +187,43 @@ static int call_fext_func(int func, int op, int feature, int state)
        return value;
 }
 
-#if IS_ENABLED(CONFIG_LEDS_CLASS)
-/* LED class callbacks */
-
-static int logolamp_set(struct led_classdev *cdev,
-                              enum led_brightness brightness)
-{
-       int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
-       int ret;
-
-       if (brightness < LED_HALF)
-               poweron = FUNC_LED_OFF;
-
-       if (brightness < LED_FULL)
-               always = FUNC_LED_OFF;
-
-       ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
-       if (ret < 0)
-               return ret;
-
-       return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
-}
-
-static int kblamps_set(struct led_classdev *cdev,
-                              enum led_brightness brightness)
-{
-       if (brightness >= LED_FULL)
-               return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON);
-       else
-               return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF);
-}
-
-static int radio_led_set(struct led_classdev *cdev,
-                               enum led_brightness brightness)
-{
-       if (brightness >= LED_FULL)
-               return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, RADIO_LED_ON);
-       else
-               return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, 0x0);
-}
-
-static int eco_led_set(struct led_classdev *cdev,
-                               enum led_brightness brightness)
-{
-       int curr;
-
-       curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0);
-       if (brightness >= LED_FULL)
-               return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON);
-       else
-               return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON);
-}
-
-static enum led_brightness logolamp_get(struct led_classdev *cdev)
-{
-       int ret;
-
-       ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
-       if (ret == FUNC_LED_ON)
-               return LED_FULL;
-
-       ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
-       if (ret == FUNC_LED_ON)
-               return LED_HALF;
-
-       return LED_OFF;
-}
-
-static enum led_brightness kblamps_get(struct led_classdev *cdev)
-{
-       enum led_brightness brightness = LED_OFF;
-
-       if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
-               brightness = LED_FULL;
-
-       return brightness;
-}
-
-static enum led_brightness radio_led_get(struct led_classdev *cdev)
-{
-       enum led_brightness brightness = LED_OFF;
-
-       if (call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON)
-               brightness = LED_FULL;
-
-       return brightness;
-}
-
-static enum led_brightness eco_led_get(struct led_classdev *cdev)
-{
-       enum led_brightness brightness = LED_OFF;
-
-       if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
-               brightness = LED_FULL;
-
-       return brightness;
-}
-#endif
-
 /* Hardware access for LCD brightness control */
 
 static int set_lcd_level(int level)
 {
-       acpi_status status = AE_OK;
-       acpi_handle handle = NULL;
-
-       vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n",
-                   level);
-
-       if (level < 0 || level >= fujitsu_bl->max_brightness)
-               return -EINVAL;
+       acpi_status status;
+       char *method;
 
-       status = acpi_get_handle(fujitsu_bl->acpi_handle, "SBLL", &handle);
-       if (ACPI_FAILURE(status)) {
-               vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
-               return -ENODEV;
+       switch (use_alt_lcd_levels) {
+       case -1:
+               if (acpi_has_method(fujitsu_bl->acpi_handle, "SBL2"))
+                       method = "SBL2";
+               else
+                       method = "SBLL";
+               break;
+       case 1:
+               method = "SBL2";
+               break;
+       default:
+               method = "SBLL";
+               break;
        }
 
-
-       status = acpi_execute_simple_method(handle, NULL, level);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       return 0;
-}
-
-static int set_lcd_level_alt(int level)
-{
-       acpi_status status = AE_OK;
-       acpi_handle handle = NULL;
-
-       vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n",
-                   level);
+       vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via %s [%d]\n",
+                   method, level);
 
        if (level < 0 || level >= fujitsu_bl->max_brightness)
                return -EINVAL;
 
-       status = acpi_get_handle(fujitsu_bl->acpi_handle, "SBL2", &handle);
+       status = acpi_execute_simple_method(fujitsu_bl->acpi_handle, method,
+                                           level);
        if (ACPI_FAILURE(status)) {
-               vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
+               vdbg_printk(FUJLAPTOP_DBG_ERROR, "Failed to evaluate %s\n",
+                           method);
                return -ENODEV;
        }
 
-       status = acpi_execute_simple_method(handle, NULL, level);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
+       fujitsu_bl->brightness_level = level;
 
        return 0;
 }
@@ -404,11 +242,6 @@ static int get_lcd_level(void)
 
        fujitsu_bl->brightness_level = state & 0x0fffffff;
 
-       if (state & 0x80000000)
-               fujitsu_bl->brightness_changed = 1;
-       else
-               fujitsu_bl->brightness_changed = 0;
-
        return fujitsu_bl->brightness_level;
 }
 
@@ -433,30 +266,17 @@ static int get_max_brightness(void)
 
 static int bl_get_brightness(struct backlight_device *b)
 {
-       return get_lcd_level();
+       return b->props.power == FB_BLANK_POWERDOWN ? 0 : get_lcd_level();
 }
 
 static int bl_update_status(struct backlight_device *b)
 {
-       int ret;
        if (b->props.power == FB_BLANK_POWERDOWN)
-               ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
-       else
-               ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
-       if (ret != 0)
-               vdbg_printk(FUJLAPTOP_DBG_ERROR,
-                       "Unable to adjust backlight power, error code %i\n",
-                       ret);
-
-       if (use_alt_lcd_levels)
-               ret = set_lcd_level_alt(b->props.brightness);
+               call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
        else
-               ret = set_lcd_level(b->props.brightness);
-       if (ret != 0)
-               vdbg_printk(FUJLAPTOP_DBG_ERROR,
-                       "Unable to adjust LCD brightness, error code %i\n",
-                       ret);
-       return ret;
+               call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
+
+       return set_lcd_level(b->props.brightness);
 }
 
 static const struct backlight_ops fujitsu_bl_ops = {
@@ -550,17 +370,18 @@ static int acpi_fujitsu_bl_input_setup(struct acpi_device *device)
        return input_register_device(fujitsu_bl->input);
 }
 
-static int fujitsu_backlight_register(void)
+static int fujitsu_backlight_register(struct acpi_device *device)
 {
-       struct backlight_properties props = {
+       const struct backlight_properties props = {
                .brightness = fujitsu_bl->brightness_level,
                .max_brightness = fujitsu_bl->max_brightness - 1,
                .type = BACKLIGHT_PLATFORM
        };
        struct backlight_device *bd;
 
-       bd = backlight_device_register("fujitsu-laptop", NULL, NULL,
-                                      &fujitsu_bl_ops, &props);
+       bd = devm_backlight_device_register(&device->dev, "fujitsu-laptop",
+                                           &device->dev, NULL,
+                                           &fujitsu_bl_ops, &props);
        if (IS_ERR(bd))
                return PTR_ERR(bd);
 
@@ -599,8 +420,6 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device)
               acpi_device_name(device), acpi_device_bid(device),
               !device->power.state ? "on" : "off");
 
-       fujitsu_bl->dev = device;
-
        if (acpi_has_method(device->handle, METHOD_NAME__INI)) {
                vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
                if (ACPI_FAILURE
@@ -609,44 +428,17 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device)
                        pr_err("_INI Method failed\n");
        }
 
-       if (use_alt_lcd_levels == -1) {
-               if (acpi_has_method(NULL, "\\_SB.PCI0.LPCB.FJEX.SBL2"))
-                       use_alt_lcd_levels = 1;
-               else
-                       use_alt_lcd_levels = 0;
-               vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as %i\n",
-                           use_alt_lcd_levels);
-       }
-
-       /* do config (detect defaults) */
-       use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
-       disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
-       vdbg_printk(FUJLAPTOP_DBG_INFO,
-                   "config: [alt interface: %d], [adjust disable: %d]\n",
-                   use_alt_lcd_levels, disable_brightness_adjust);
-
        if (get_max_brightness() <= 0)
                fujitsu_bl->max_brightness = FUJITSU_LCD_N_LEVELS;
        get_lcd_level();
 
-       error = fujitsu_backlight_register();
+       error = fujitsu_backlight_register(device);
        if (error)
                return error;
 
        return 0;
 }
 
-static int acpi_fujitsu_bl_remove(struct acpi_device *device)
-{
-       struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device);
-
-       backlight_device_unregister(fujitsu_bl->bl_device);
-
-       fujitsu_bl->acpi_handle = NULL;
-
-       return 0;
-}
-
 /* Brightness notify */
 
 static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event)
@@ -667,19 +459,14 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event)
        get_lcd_level();
        newb = fujitsu_bl->brightness_level;
 
-       vdbg_printk(FUJLAPTOP_DBG_TRACE,
-                   "brightness button event [%i -> %i (%i)]\n",
-                   oldb, newb, fujitsu_bl->brightness_changed);
+       vdbg_printk(FUJLAPTOP_DBG_TRACE, "brightness button event [%i -> %i]\n",
+                   oldb, newb);
 
        if (oldb == newb)
                return;
 
-       if (disable_brightness_adjust != 1) {
-               if (use_alt_lcd_levels)
-                       set_lcd_level_alt(newb);
-               else
-                       set_lcd_level(newb);
-       }
+       if (!disable_brightness_adjust)
+               set_lcd_level(newb);
 
        sparse_keymap_report_event(input, oldb < newb, 1, true);
 }
@@ -811,9 +598,181 @@ static void fujitsu_laptop_platform_remove(void)
        platform_device_unregister(fujitsu_laptop->pf_device);
 }
 
-static int acpi_fujitsu_laptop_add(struct acpi_device *device)
+static int logolamp_set(struct led_classdev *cdev,
+                       enum led_brightness brightness)
+{
+       int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
+       int ret;
+
+       if (brightness < LED_HALF)
+               poweron = FUNC_LED_OFF;
+
+       if (brightness < LED_FULL)
+               always = FUNC_LED_OFF;
+
+       ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
+       if (ret < 0)
+               return ret;
+
+       return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
+}
+
+static enum led_brightness logolamp_get(struct led_classdev *cdev)
+{
+       int ret;
+
+       ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
+       if (ret == FUNC_LED_ON)
+               return LED_FULL;
+
+       ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
+       if (ret == FUNC_LED_ON)
+               return LED_HALF;
+
+       return LED_OFF;
+}
+
+static struct led_classdev logolamp_led = {
+       .name = "fujitsu::logolamp",
+       .brightness_set_blocking = logolamp_set,
+       .brightness_get = logolamp_get
+};
+
+static int kblamps_set(struct led_classdev *cdev,
+                      enum led_brightness brightness)
+{
+       if (brightness >= LED_FULL)
+               return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
+                                     FUNC_LED_ON);
+       else
+               return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
+                                     FUNC_LED_OFF);
+}
+
+static enum led_brightness kblamps_get(struct led_classdev *cdev)
+{
+       enum led_brightness brightness = LED_OFF;
+
+       if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
+               brightness = LED_FULL;
+
+       return brightness;
+}
+
+static struct led_classdev kblamps_led = {
+       .name = "fujitsu::kblamps",
+       .brightness_set_blocking = kblamps_set,
+       .brightness_get = kblamps_get
+};
+
+static int radio_led_set(struct led_classdev *cdev,
+                        enum led_brightness brightness)
+{
+       if (brightness >= LED_FULL)
+               return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON,
+                                     RADIO_LED_ON);
+       else
+               return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, 0x0);
+}
+
+static enum led_brightness radio_led_get(struct led_classdev *cdev)
+{
+       enum led_brightness brightness = LED_OFF;
+
+       if (call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON)
+               brightness = LED_FULL;
+
+       return brightness;
+}
+
+static struct led_classdev radio_led = {
+       .name = "fujitsu::radio_led",
+       .brightness_set_blocking = radio_led_set,
+       .brightness_get = radio_led_get,
+       .default_trigger = "rfkill-any"
+};
+
+static int eco_led_set(struct led_classdev *cdev,
+                      enum led_brightness brightness)
+{
+       int curr;
+
+       curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0);
+       if (brightness >= LED_FULL)
+               return call_fext_func(FUNC_LEDS, 0x1, ECO_LED,
+                                     curr | ECO_LED_ON);
+       else
+               return call_fext_func(FUNC_LEDS, 0x1, ECO_LED,
+                                     curr & ~ECO_LED_ON);
+}
+
+static enum led_brightness eco_led_get(struct led_classdev *cdev)
+{
+       enum led_brightness brightness = LED_OFF;
+
+       if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
+               brightness = LED_FULL;
+
+       return brightness;
+}
+
+static struct led_classdev eco_led = {
+       .name = "fujitsu::eco_led",
+       .brightness_set_blocking = eco_led_set,
+       .brightness_get = eco_led_get
+};
+
+static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
 {
        int result = 0;
+
+       if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
+               result = devm_led_classdev_register(&device->dev,
+                                                   &logolamp_led);
+               if (result)
+                       pr_err("Could not register LED handler for logo lamp, error %i\n",
+                              result);
+       }
+
+       if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
+           (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
+               result = devm_led_classdev_register(&device->dev, &kblamps_led);
+               if (result)
+                       pr_err("Could not register LED handler for keyboard lamps, error %i\n",
+                              result);
+       }
+
+       /*
+        * BTNI bit 24 seems to indicate the presence of a radio toggle
+        * button in place of a slide switch, and all such machines appear
+        * to also have an RF LED.  Therefore use bit 24 as an indicator
+        * that an RF LED is present.
+        */
+       if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) {
+               result = devm_led_classdev_register(&device->dev, &radio_led);
+               if (result)
+                       pr_err("Could not register LED handler for radio LED, error %i\n",
+                              result);
+       }
+
+       /* Support for eco led is not always signaled in bit corresponding
+        * to the bit used to control the led. According to the DSDT table,
+        * bit 14 seems to indicate presence of said led as well.
+        * Confirm by testing the status.
+        */
+       if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
+           (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
+               result = devm_led_classdev_register(&device->dev, &eco_led);
+               if (result)
+                       pr_err("Could not register LED handler for eco LED, error %i\n",
+                              result);
+       }
+
+       return result;
+}
+
+static int acpi_fujitsu_laptop_add(struct acpi_device *device)
+{
        int state = 0;
        int error;
        int i;
@@ -894,67 +853,14 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device)
        if (error)
                goto err_free_fifo;
 
-#if IS_ENABLED(CONFIG_LEDS_CLASS)
-       if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
-               result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
-                                               &logolamp_led);
-               if (result == 0) {
-                       fujitsu_laptop->logolamp_registered = 1;
-               } else {
-                       pr_err("Could not register LED handler for logo lamp, error %i\n",
-                              result);
-               }
-       }
-
-       if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
-          (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
-               result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
-                                               &kblamps_led);
-               if (result == 0) {
-                       fujitsu_laptop->kblamps_registered = 1;
-               } else {
-                       pr_err("Could not register LED handler for keyboard lamps, error %i\n",
-                              result);
-               }
-       }
-
-       /*
-        * BTNI bit 24 seems to indicate the presence of a radio toggle
-        * button in place of a slide switch, and all such machines appear
-        * to also have an RF LED.  Therefore use bit 24 as an indicator
-        * that an RF LED is present.
-        */
-       if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) {
-               result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
-                                               &radio_led);
-               if (result == 0) {
-                       fujitsu_laptop->radio_led_registered = 1;
-               } else {
-                       pr_err("Could not register LED handler for radio LED, error %i\n",
-                              result);
-               }
-       }
-
-       /* Support for eco led is not always signaled in bit corresponding
-        * to the bit used to control the led. According to the DSDT table,
-        * bit 14 seems to indicate presence of said led as well.
-        * Confirm by testing the status.
-       */
-       if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
-          (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
-               result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
-                                               &eco_led);
-               if (result == 0) {
-                       fujitsu_laptop->eco_led_registered = 1;
-               } else {
-                       pr_err("Could not register LED handler for eco LED, error %i\n",
-                              result);
-               }
-       }
-#endif
+       error = acpi_fujitsu_laptop_leds_register(device);
+       if (error)
+               goto err_remove_platform_device;
 
-       return result;
+       return 0;
 
+err_remove_platform_device:
+       fujitsu_laptop_platform_remove();
 err_free_fifo:
        kfifo_free(&fujitsu_laptop->fifo);
 err_stop:
@@ -965,26 +871,10 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device)
 {
        struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device);
 
-#if IS_ENABLED(CONFIG_LEDS_CLASS)
-       if (fujitsu_laptop->logolamp_registered)
-               led_classdev_unregister(&logolamp_led);
-
-       if (fujitsu_laptop->kblamps_registered)
-               led_classdev_unregister(&kblamps_led);
-
-       if (fujitsu_laptop->radio_led_registered)
-               led_classdev_unregister(&radio_led);
-
-       if (fujitsu_laptop->eco_led_registered)
-               led_classdev_unregister(&eco_led);
-#endif
-
        fujitsu_laptop_platform_remove();
 
        kfifo_free(&fujitsu_laptop->fifo);
 
-       fujitsu_laptop->acpi_handle = NULL;
-
        return 0;
 }
 
@@ -1077,7 +967,6 @@ static struct acpi_driver acpi_fujitsu_bl_driver = {
        .ids = fujitsu_bl_device_ids,
        .ops = {
                .add = acpi_fujitsu_bl_add,
-               .remove = acpi_fujitsu_bl_remove,
                .notify = acpi_fujitsu_bl_notify,
                },
 };
@@ -1172,11 +1061,10 @@ static void __exit fujitsu_cleanup(void)
 module_init(fujitsu_init);
 module_exit(fujitsu_cleanup);
 
-module_param(use_alt_lcd_levels, uint, 0644);
-MODULE_PARM_DESC(use_alt_lcd_levels,
-                "Use alternative interface for lcd_levels (needed for Lifebook s6410).");
-module_param(disable_brightness_adjust, uint, 0644);
-MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment .");
+module_param(use_alt_lcd_levels, int, 0644);
+MODULE_PARM_DESC(use_alt_lcd_levels, "Interface used for setting LCD brightness level (-1 = auto, 0 = force SBLL, 1 = force SBL2)");
+module_param(disable_brightness_adjust, bool, 0644);
+MODULE_PARM_DESC(disable_brightness_adjust, "Disable LCD brightness adjustment");
 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
 module_param_named(debug, dbg_level, uint, 0644);
 MODULE_PARM_DESC(debug, "Sets debug level bit-mask");