Platform: Brightness quirk for samsung laptop driver
authorJason Stubbs <jasonbstubbs@gmail.com>
Tue, 20 Sep 2011 16:16:13 +0000 (09:16 -0700)
committerMatthew Garrett <mjg@redhat.com>
Mon, 24 Oct 2011 14:52:35 +0000 (16:52 +0200)
On some Samsung laptops the brightness regulation works slightly different.
All SABI commands except for set_brightness work as expected. The behaviour
of set_brightness is as follows:

- Setting a new brightness will only step one level toward the new brightness
  level. For example, setting a level of 5 when the current level is 2 will
  result in a brightness level of 3.
- A spurious KEY_BRIGHTNESS_UP or KEY_BRIGHTNESS_DOWN event is also generated
  along with the change in brightness.
- Neither of the above two issues occur when changing from/to brightness
  level 0.

This patch adds detection and a non-intrusive workaround for the above issues.

Signed-off-by: Jason Stubbs <jasonbstubbs@gmail.com>
Tested-by: David Herrmann <dh.herrmann@googlemail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
drivers/platform/x86/samsung-laptop.c

index 4d3bed4..6474e42 100644 (file)
@@ -226,6 +226,7 @@ static struct backlight_device *backlight_device;
 static struct mutex sabi_mutex;
 static struct platform_device *sdev;
 static struct rfkill *rfk;
+static bool has_stepping_quirk;
 
 static int force;
 module_param(force, bool, 0);
@@ -382,6 +383,17 @@ static void set_brightness(u8 user_brightness)
 {
        u8 user_level = user_brightness + sabi_config->min_brightness;
 
+       if (has_stepping_quirk && user_level != 0) {
+               /*
+                * short circuit if the specified level is what's already set
+                * to prevent the screen from flickering needlessly
+                */
+               if (user_brightness == read_brightness())
+                       return;
+
+               sabi_set_command(sabi_config->commands.set_brightness, 0);
+       }
+
        sabi_set_command(sabi_config->commands.set_brightness, user_level);
 }
 
@@ -390,6 +402,34 @@ static int get_brightness(struct backlight_device *bd)
        return (int)read_brightness();
 }
 
+static void check_for_stepping_quirk(void)
+{
+       u8 initial_level = read_brightness();
+       u8 check_level;
+
+       /*
+        * Some laptops exhibit the strange behaviour of stepping toward
+        * (rather than setting) the brightness except when changing to/from
+        * brightness level 0. This behaviour is checked for here and worked
+        * around in set_brightness.
+        */
+
+       if (initial_level <= 2)
+               check_level = initial_level + 2;
+       else
+               check_level = initial_level - 2;
+
+       has_stepping_quirk = false;
+       set_brightness(check_level);
+
+       if (read_brightness() != check_level) {
+               has_stepping_quirk = true;
+               pr_info("enabled workaround for brightness stepping quirk\n");
+       }
+
+       set_brightness(initial_level);
+}
+
 static int update_status(struct backlight_device *bd)
 {
        set_brightness(bd->props.brightness);
@@ -805,6 +845,9 @@ static int __init samsung_init(void)
                }
        }
 
+       /* Check for stepping quirk */
+       check_for_stepping_quirk();
+
        /* knock up a platform device to hang stuff off of */
        sdev = platform_device_register_simple("samsung", -1, NULL, 0);
        if (IS_ERR(sdev))