Hi Luke,
On 6/30/23 06:17, Luke D. Jones wrote:
Add support for the WMI methods used to turn off and adjust the
brightness of the secondary "screenpad" device found on some high-
end
ASUS laptops like the GX650P series and others.
These methods are utilised in a new backlight device named
asus_screenpad.
Signed-off-by: Luke D. Jones <luke@xxxxxxxxxx>
Thank you for your work on this. I have one small change request
and then v5 should be ready for merging, see me inline comment
below.
---
drivers/platform/x86/asus-wmi.c | 128
+++++++++++++++++++++
drivers/platform/x86/asus-wmi.h | 1 +
include/linux/platform_data/x86/asus-wmi.h | 4 +
3 files changed, 133 insertions(+)
diff --git a/drivers/platform/x86/asus-wmi.c
b/drivers/platform/x86/asus-wmi.c
index 62cee13f5576..967c92ceb041 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -25,6 +25,7 @@
#include <linux/input/sparse-keymap.h>
#include <linux/kernel.h>
#include <linux/leds.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
@@ -212,6 +213,7 @@ struct asus_wmi {
struct input_dev *inputdev;
struct backlight_device *backlight_device;
+ struct backlight_device *screenpad_backlight_device;
struct platform_device *platform_device;
struct led_classdev wlan_led;
@@ -3839,6 +3841,123 @@ static int is_display_toggle(int code)
return 0;
}
+/* Screenpad backlight
*******************************************************/
+
+static int read_screenpad_backlight_power(struct asus_wmi *asus)
+{
+ int ret;
+
+ ret = asus_wmi_get_devstate_simple(asus,
ASUS_WMI_DEVID_SCREENPAD_POWER);
+ if (ret < 0)
+ return ret;
+ /* 1 == powered */
+ return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+}
+
+static int read_screenpad_brightness(struct backlight_device *bd)
+{
+ struct asus_wmi *asus = bl_get_data(bd);
+ u32 retval;
+ int err;
+
+ err = read_screenpad_backlight_power(asus);
+ if (err < 0)
+ return err;
+ /* The device brightness can only be read if powered, so
return stored */
+ if (err == FB_BLANK_POWERDOWN)
+ return asus->driver->screenpad_brightness;
+
+ err = asus_wmi_get_devstate(asus,
ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval);
+ if (err < 0)
+ return err;
+
+ return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
+}
+
+static int update_screenpad_bl_status(struct backlight_device
*bd)
+{
+ struct asus_wmi *asus = bl_get_data(bd);
+ int power, err = 0;
+ u32 ctrl_param;
+
+ power = read_screenpad_backlight_power(asus);
+ if (power < 0)
+ return power;
+
+ if (bd->props.power != power) {
+ if (power != FB_BLANK_UNBLANK) {
+ /* Only brightness > 0 can power it back
on
*/
+ ctrl_param = max(1, asus->driver-
screenpad_brightness);
+ err =
asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT,
+ ctrl_param,
NULL);
+ } else {
+ err =
asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL);
+ }
+ } else if (power == FB_BLANK_UNBLANK) {
+ /* Only set brightness if powered on or we get
invalid/unsync state */
+ ctrl_param = bd->props.brightness;
+ err =
asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param,
NULL);
+ }
+
+ /* Ensure brightness is stored to turn back on with */
+ asus->driver->screenpad_brightness = bd->props.brightness;
+
+ return err;
+}
+
+static const struct backlight_ops asus_screenpad_bl_ops = {
+ .get_brightness = read_screenpad_brightness,
+ .update_status = update_screenpad_bl_status,
+ .options = BL_CORE_SUSPENDRESUME,
+};
+
+static int asus_screenpad_init(struct asus_wmi *asus)
+{
+ struct backlight_device *bd;
+ struct backlight_properties props;
+ int err, power;
+ int brightness = 0;
+
+ power = read_screenpad_backlight_power(asus);
+ if (power < 0)
+ return power;
+
+ if (power != FB_BLANK_POWERDOWN) {
+ err = asus_wmi_get_devstate(asus,
ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness);
+ if (err < 0)
+ return err;
+ }
+ /* default to an acceptable min brightness on boot if too
low */
+ if (brightness < 60)
+ brightness = 60;
If settings below 60 are no good, then the correct way to handle
this is to limit the range to 0 - (255-60) and add / substract
60 when setting / getting the brightness.
E.g. do something like this:
#define SCREENPAD_MIN_BRIGHTNESS 60
#define SCREENPAD_MAX_BRIGHTNESS 255
props.max_brightness = SCREENPAD_MAX_BRIGHTNESS -
SCREENPAD_MIN_BRIGHTNESS;
And in update_screenpad_bl_status() do:
ctrl_param = bd->props.brightness +
SCREENPAD_MIN_BRIGHTNESS;
And when reading the brightness substract SCREENPAD_MIN_BRIGHTNESS,
clamping to a minimum value of 0.
This avoids a dead-zone in the brightness range between 0-60 .