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

Message ID 20230503040207.257406-1-luke@ljones.dev
State New
Headers
Series platform/x86: asus-wmi: add support for ASUS screenpad |

Commit Message

Luke Jones May 3, 2023, 4:02 a.m. UTC
  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@ljones.dev>
---
 .../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(+)
  

Comments

Barnabás Pőcze May 3, 2023, 5:46 p.m. UTC | #1
Hi


2023. május 3., szerda 6:02 keltezéssel, Luke D. Jones <luke@ljones.dev> írta:

> 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.

Is it this one: https://www.asus.com/content/rog-screenpad-plus/ ?
Or is the "plus" version something different?

If it's a "proper" screen, wouldn't it be better to add support for it
in the respective subsystems? E.g. why not register a backlight device?


> 
> Signed-off-by: Luke D. Jones <luke@ljones.dev>
> ---
> [...]


Regards,
Barnabás Pőcze
  
Luke Jones May 3, 2023, 9:22 p.m. UTC | #2
On Wed, May 3 2023 at 17:46:53 +0000, Barnabás Pőcze 
<pobrn@protonmail.com> wrote:
> Hi
> 
> 
> 2023. május 3., szerda 6:02 keltezéssel, Luke D. Jones 
> <luke@ljones.dev> írta:
> 
>>  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.
> 
> Is it this one: https://www.asus.com/content/rog-screenpad-plus/ ?
> Or is the "plus" version something different?
> 
> If it's a "proper" screen, wouldn't it be better to add support for it
> in the respective subsystems? E.g. why not register a backlight 
> device?

I think it is similar yes, likely the same thing.

Adding as a proper backlight is what I wanted to do but at first blush 
I wasn't sure.

Looking at include/linux/backlight.h + some examples it looks clear 
now. I'll try to
work up a revised patch and get it tested by the folks with the actual 
laptop.

My only possible issue would be how to handle the on/off part?

Cheers,
Luke.
  
kernel test robot May 4, 2023, 12:19 p.m. UTC | #3
Hi Luke,

kernel test robot noticed the following build warnings:

[auto build test WARNING on groeck-staging/hwmon-next]
[also build test WARNING on linus/master v6.3 next-20230428]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Luke-D-Jones/platform-x86-asus-wmi-add-support-for-ASUS-screenpad/20230503-120548
base:   https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next
patch link:    https://lore.kernel.org/r/20230503040207.257406-1-luke%40ljones.dev
patch subject: [PATCH] platform/x86: asus-wmi: add support for ASUS screenpad
reproduce:
        # https://github.com/intel-lab-lkp/linux/commit/ff073483de3660059cb167912c02e51226e4b32e
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Luke-D-Jones/platform-x86-asus-wmi-add-support-for-ASUS-screenpad/20230503-120548
        git checkout ff073483de3660059cb167912c02e51226e4b32e
        make menuconfig
        # enable CONFIG_COMPILE_TEST, CONFIG_WARN_MISSING_DOCUMENTS, CONFIG_WARN_ABI_ERRORS
        make htmldocs

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202305042007.28rKu9cK-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> Documentation/ABI/testing/sysfs-platform-asus-wmi:114: WARNING: Unexpected indentation.

vim +114 Documentation/ABI/testing/sysfs-platform-asus-wmi

 > 114	Date:		May 2023
  
Luke Jones May 5, 2023, 4:36 a.m. UTC | #4
On Thu, May 4 2023 at 09:22:03 +1200, Luke Jones <luke@ljones.dev> 
wrote:
> 
> 
> On Wed, May 3 2023 at 17:46:53 +0000, Barnabás Pőcze 
> <pobrn@protonmail.com> wrote:
>> Hi
>> 
>> 
>> 2023. május 3., szerda 6:02 keltezéssel, Luke D. Jones 
>> <luke@ljones.dev> írta:
>> 
>>>  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.
>> 
>> Is it this one: https://www.asus.com/content/rog-screenpad-plus/ ?
>> Or is the "plus" version something different?
>> 
>> If it's a "proper" screen, wouldn't it be better to add support for 
>> it
>> in the respective subsystems? E.g. why not register a backlight 
>> device?
> 
> I think it is similar yes, likely the same thing.
> 
> Adding as a proper backlight is what I wanted to do but at first 
> blush I wasn't sure.
> 
> Looking at include/linux/backlight.h + some examples it looks clear 
> now. I'll try to
> work up a revised patch and get it tested by the folks with the 
> actual laptop.
> 
> My only possible issue would be how to handle the on/off part?
> 
> Cheers,
> Luke.

This has now been addressed with "[PATCH v2 0/1] platform/x86: 
asus-wmi: add support for ASUS screenpad" at 
https://lkml.org/lkml/2023/5/5/9
  

Patch

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@ljones.dev>
+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@ljones.dev>
+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