[PATCH] platform/x86: asus-wmi: add support for ASUS screenpad

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.

Signed-off-by: Luke D. Jones <luke@xxxxxxxxxx>
---
 .../ABI/testing/sysfs-platform-asus-wmi       |  20 +++
 drivers/platform/x86/asus-wmi.c               | 121 ++++++++++++++++++
 include/linux/platform_data/x86/asus-wmi.h    |   4 +
 3 files changed, 145 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
index a77a004a1baa..97028c919c03 100644
--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
@@ -98,3 +98,23 @@ Description:
 		Enable an LCD response-time boost to reduce or remove ghosting:
 			* 0 - Disable,
 			* 1 - Enable
+
+What:		/sys/devices/platform/<platform>/screenpad_enable
+Date:		May 2023
+KernelVersion:	6.4
+Contact:	"Luke Jones" <luke@xxxxxxxxxx>
+Description:
+		Enable the secondary "screenpad" screen found on some ASUS
+		devices which is typically a short screen mounted above the
+		keyboard and below the main screen:
+			* 0 - Disable,
+			* 1 - Enable
+
+What:		/sys/devices/platform/<platform>/screenpad_brightness
+Date:		May 2023
+KernelVersion:	6.4
+Contact:	"Luke Jones" <luke@xxxxxxxxxx>
+Description:
+		Control the brightness of the secondary "screenpad" screen
+		found on some ASUS devices:
+			* 0-255 where 255 is maximum brightness
\ No newline at end of file
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 1038dfdcdd32..bd3975be9060 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -241,6 +241,10 @@ struct asus_wmi {
 	bool dgpu_disable_available;
 	bool gpu_mux_mode_available;
 
+	bool screenpad_enable_available;
+	bool screenpad_brightness_available;
+	u8 screenpad_last_brightness;
+
 	bool kbd_rgb_mode_available;
 	bool kbd_rgb_state_available;
 
@@ -733,6 +737,113 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(gpu_mux_mode);
 
+/* screenpad switch *************************************************************/
+static ssize_t screenpad_enable_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct asus_wmi *asus = dev_get_drvdata(dev);
+	int result;
+
+	result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_DISABLE);
+	if (result < 0)
+		return result;
+
+	return sysfs_emit(buf, "%d\n", result);
+}
+
+static ssize_t screenpad_enable_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct asus_wmi *asus = dev_get_drvdata(dev);
+	int result, err;
+	u8 enable;
+
+	err = kstrtou8(buf, 10, &enable);
+	if (err)
+		return err;
+
+	if (enable > 1)
+		return -EINVAL;
+
+	if (enable == 0) {
+		/* Get and store brightness before disabling */
+		asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &result);
+		if (result < 0)
+			return result;
+		asus->screenpad_last_brightness = result & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
+
+		err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_DISABLE, enable, &result);
+	} else {
+		/* Setting the brightness is what re-enables the screenpad */
+		err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT,
+								asus->screenpad_last_brightness,
+								&result);
+	}
+	if (err) {
+		dev_err(dev, "Failed to set screenpad_enable: %d\n", err);
+		return err;
+	}
+	if (result != 1) {
+		dev_warn(dev, "Failed to set screenpad_enable (result): 0x%x\n", result);
+		return -EIO;
+	}
+
+	sysfs_notify(&asus->platform_device->dev.kobj, NULL, "screenpad_enable");
+
+	return count;
+}
+static DEVICE_ATTR_RW(screenpad_enable);
+
+/* screenpad brightness *************************************************************/
+static ssize_t screenpad_brightness_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct asus_wmi *asus = dev_get_drvdata(dev);
+	int result;
+
+	/* Check if the screen is enabled, if not, return last saved brightness */
+	result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_DISABLE);
+	if (result < 0)
+		return result;
+	if (!result)
+		return asus->screenpad_last_brightness;
+
+	asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &result);
+	if (result < 0)
+		return result;
+
+	return sysfs_emit(buf, "%d\n", result & ASUS_WMI_DSTS_BRIGHTNESS_MASK);
+}
+
+static ssize_t screenpad_brightness_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct asus_wmi *asus = dev_get_drvdata(dev);
+	int result, err;
+	u8 brightness;
+
+	err = kstrtou8(buf, 10, &brightness);
+	if (err)
+		return err;
+
+	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, brightness, &result);
+	if (err) {
+		dev_err(dev, "Failed to set screenpad_brightness: %d\n", err);
+		return err;
+	}
+	if (result != 1) {
+		dev_warn(dev, "Failed to set screenpad_brightness (result): 0x%x\n", result);
+		return -EIO;
+	}
+
+	sysfs_notify(&asus->platform_device->dev.kobj, NULL, "screenpad_brightness");
+
+	return count;
+}
+static DEVICE_ATTR_RW(screenpad_brightness);
+
 /* TUF Laptop Keyboard RGB Modes **********************************************/
 static ssize_t kbd_rgb_mode_store(struct device *dev,
 				 struct device_attribute *attr,
@@ -3465,6 +3576,8 @@ static struct attribute *platform_attributes[] = {
 	&dev_attr_egpu_enable.attr,
 	&dev_attr_dgpu_disable.attr,
 	&dev_attr_gpu_mux_mode.attr,
+	&dev_attr_screenpad_enable.attr,
+	&dev_attr_screenpad_brightness.attr,
 	&dev_attr_lid_resume.attr,
 	&dev_attr_als_enable.attr,
 	&dev_attr_fan_boost_mode.attr,
@@ -3497,6 +3610,10 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
 		ok = asus->dgpu_disable_available;
 	else if (attr == &dev_attr_gpu_mux_mode.attr)
 		ok = asus->gpu_mux_mode_available;
+	else if (attr == &dev_attr_screenpad_enable.attr)
+		ok = asus->screenpad_enable_available;
+	else if (attr == &dev_attr_screenpad_brightness.attr)
+		ok = asus->screenpad_brightness_available;
 	else if (attr == &dev_attr_fan_boost_mode.attr)
 		ok = asus->fan_boost_mode_available;
 	else if (attr == &dev_attr_throttle_thermal_policy.attr)
@@ -3760,6 +3877,10 @@ static int asus_wmi_add(struct platform_device *pdev)
 	asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
 	asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
 	asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX);
+	asus->screenpad_enable_available = asus_wmi_dev_is_present(asus,
+								ASUS_WMI_DEVID_SCREENPAD_DISABLE);
+	asus->screenpad_brightness_available = asus_wmi_dev_is_present(asus,
+								ASUS_WMI_DEVID_SCREENPAD_LIGHT);
 	asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
 	asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
 	asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 28234dc9fa6a..978627aac87c 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -58,6 +58,10 @@
 #define ASUS_WMI_DEVID_KBD_BACKLIGHT	0x00050021
 #define ASUS_WMI_DEVID_LIGHT_SENSOR	0x00050022 /* ?? */
 #define ASUS_WMI_DEVID_LIGHTBAR		0x00050025
+/* This can only be used to disable the screen, not re-enable */
+#define ASUS_WMI_DEVID_SCREENPAD_DISABLE	0x00050031
+/* Writing a brightness re-enables the screen if disabled */
+#define ASUS_WMI_DEVID_SCREENPAD_LIGHT	0x00050032
 #define ASUS_WMI_DEVID_FAN_BOOST_MODE	0x00110018
 #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
 
-- 
2.40.0




[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux