diff mbox series

[v4,1/9] platform/x86: asus-wmi: add support for 2024 ROG Mini-LED

Message ID 20240404001652.86207-2-luke@ljones.dev (mailing list archive)
State Accepted, archived
Headers show
Series asus-wmi: add new features, clean up, fixes | expand

Commit Message

Luke D. Jones April 4, 2024, 12:16 a.m. UTC
Support the 2024 mini-led backlight and adjust the related functions
to select the relevant dev-id. Also add `available_mini_led_mode` to the
platform sysfs since the available mini-led levels can be different.

Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 .../ABI/testing/sysfs-platform-asus-wmi       |  8 ++
 drivers/platform/x86/asus-wmi.c               | 96 +++++++++++++++++--
 include/linux/platform_data/x86/asus-wmi.h    |  1 +
 3 files changed, 95 insertions(+), 10 deletions(-)

Comments

Ilpo Järvinen April 4, 2024, 9:33 a.m. UTC | #1
On Thu, 4 Apr 2024, Luke D. Jones wrote:

> Support the 2024 mini-led backlight and adjust the related functions
> to select the relevant dev-id. Also add `available_mini_led_mode` to the
> platform sysfs since the available mini-led levels can be different.
> 
> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
> signed-off-by: Luke D. Jones <luke@ljones.dev>
> ---
>  .../ABI/testing/sysfs-platform-asus-wmi       |  8 ++
>  drivers/platform/x86/asus-wmi.c               | 96 +++++++++++++++++--
>  include/linux/platform_data/x86/asus-wmi.h    |  1 +
>  3 files changed, 95 insertions(+), 10 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> index 8a7e25bde085..ef1ac1a20a71 100644
> --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
> +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> @@ -126,6 +126,14 @@ Description:
>  		Change the mini-LED mode:
>  			* 0 - Single-zone,
>  			* 1 - Multi-zone
> +			* 2 - Multi-zone strong (available on newer generation mini-led)
> +
> +What:		/sys/devices/platform/<platform>/available_mini_led_mode
> +Date:		Apr 2024
> +KernelVersion:	6.10
> +Contact:	"Luke Jones" <luke@ljones.dev>
> +Description:
> +		List the available mini-led modes.
>  
>  What:		/sys/devices/platform/<platform>/ppt_pl1_spl
>  Date:		Jun 2023
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 3f07bbf809ef..aa2a3b402e33 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -126,6 +126,17 @@ module_param(fnlock_default, bool, 0444);
>  #define ASUS_SCREENPAD_BRIGHT_MAX 255
>  #define ASUS_SCREENPAD_BRIGHT_DEFAULT 60
>  
> +#define ASUS_MINI_LED_MODE_MASK		0x03
> +/* Standard modes for devices with only on/off */
> +#define ASUS_MINI_LED_OFF		0x00
> +#define ASUS_MINI_LED_ON		0x01
> +/* New mode on some devices, define here to clarify remapping later */
> +#define ASUS_MINI_LED_STRONG_MODE	0x02
> +/* New modes for devices with 3 mini-led mode types */
> +#define ASUS_MINI_LED_2024_WEAK		0x00
> +#define ASUS_MINI_LED_2024_STRONG	0x01
> +#define ASUS_MINI_LED_2024_OFF		0x02
> +
>  /* Controls the power state of the USB0 hub on ROG Ally which input is on */
>  #define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE"
>  /* 300ms so far seems to produce a reliable result on AC and battery */
> @@ -288,7 +299,7 @@ struct asus_wmi {
>  	bool battery_rsoc_available;
>  
>  	bool panel_overdrive_available;
> -	bool mini_led_mode_available;
> +	u32 mini_led_dev_id;
>  
>  	struct hotplug_slot hotplug_slot;
>  	struct mutex hotplug_lock;
> @@ -2108,13 +2119,33 @@ static ssize_t mini_led_mode_show(struct device *dev,
>  				   struct device_attribute *attr, char *buf)
>  {
>  	struct asus_wmi *asus = dev_get_drvdata(dev);
> -	int result;
> +	u32 value;
> +	int err;
>  
> -	result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
> -	if (result < 0)
> -		return result;
> +	err = asus_wmi_get_devstate(asus, asus->mini_led_dev_id, &value);
> +	if (err < 0)
> +		return err;
> +	value = value & ASUS_MINI_LED_MODE_MASK;
>  
> -	return sysfs_emit(buf, "%d\n", result);
> +	/*
> +	 * Remap the mode values to match previous generation mini-led. The last gen
> +	 * WMI 0 == off, while on this version WMI 2 ==off (flipped).
> +	 */
> +	if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
> +		switch (value) {
> +		case ASUS_MINI_LED_2024_WEAK:
> +			value = ASUS_MINI_LED_ON;
> +			break;
> +		case ASUS_MINI_LED_2024_STRONG:
> +			value = ASUS_MINI_LED_STRONG_MODE;
> +			break;
> +		case ASUS_MINI_LED_2024_OFF:
> +			value = ASUS_MINI_LED_OFF;
> +			break;
> +		}
> +	}
> +
> +	return sysfs_emit(buf, "%d\n", value);
>  }
>  
>  static ssize_t mini_led_mode_store(struct device *dev,
> @@ -2130,11 +2161,32 @@ static ssize_t mini_led_mode_store(struct device *dev,
>  	if (result)
>  		return result;
>  
> -	if (mode > 1)
> +	if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE &&
> +		mode > ASUS_MINI_LED_ON)
> +		return -EINVAL;
> +	if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 &&
> +		mode > ASUS_MINI_LED_STRONG_MODE)

The if condition continations should not be indented to the same level as 
its statement block because it confuses the reader. Hans might be able to 
fix this while applying though so I'm not sure if it's necessary to send a 
new version just because of this.
Hans de Goede April 8, 2024, 4:32 p.m. UTC | #2
Hi,

On 4/4/24 11:33 AM, Ilpo Järvinen wrote:
> On Thu, 4 Apr 2024, Luke D. Jones wrote:
> 
>> Support the 2024 mini-led backlight and adjust the related functions
>> to select the relevant dev-id. Also add `available_mini_led_mode` to the
>> platform sysfs since the available mini-led levels can be different.
>>
>> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
>> signed-off-by: Luke D. Jones <luke@ljones.dev>
>> ---
>>  .../ABI/testing/sysfs-platform-asus-wmi       |  8 ++
>>  drivers/platform/x86/asus-wmi.c               | 96 +++++++++++++++++--
>>  include/linux/platform_data/x86/asus-wmi.h    |  1 +
>>  3 files changed, 95 insertions(+), 10 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
>> index 8a7e25bde085..ef1ac1a20a71 100644
>> --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
>> +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
>> @@ -126,6 +126,14 @@ Description:
>>  		Change the mini-LED mode:
>>  			* 0 - Single-zone,
>>  			* 1 - Multi-zone
>> +			* 2 - Multi-zone strong (available on newer generation mini-led)
>> +
>> +What:		/sys/devices/platform/<platform>/available_mini_led_mode
>> +Date:		Apr 2024
>> +KernelVersion:	6.10
>> +Contact:	"Luke Jones" <luke@ljones.dev>
>> +Description:
>> +		List the available mini-led modes.
>>  
>>  What:		/sys/devices/platform/<platform>/ppt_pl1_spl
>>  Date:		Jun 2023
>> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
>> index 3f07bbf809ef..aa2a3b402e33 100644
>> --- a/drivers/platform/x86/asus-wmi.c
>> +++ b/drivers/platform/x86/asus-wmi.c
>> @@ -126,6 +126,17 @@ module_param(fnlock_default, bool, 0444);
>>  #define ASUS_SCREENPAD_BRIGHT_MAX 255
>>  #define ASUS_SCREENPAD_BRIGHT_DEFAULT 60
>>  
>> +#define ASUS_MINI_LED_MODE_MASK		0x03
>> +/* Standard modes for devices with only on/off */
>> +#define ASUS_MINI_LED_OFF		0x00
>> +#define ASUS_MINI_LED_ON		0x01
>> +/* New mode on some devices, define here to clarify remapping later */
>> +#define ASUS_MINI_LED_STRONG_MODE	0x02
>> +/* New modes for devices with 3 mini-led mode types */
>> +#define ASUS_MINI_LED_2024_WEAK		0x00
>> +#define ASUS_MINI_LED_2024_STRONG	0x01
>> +#define ASUS_MINI_LED_2024_OFF		0x02
>> +
>>  /* Controls the power state of the USB0 hub on ROG Ally which input is on */
>>  #define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE"
>>  /* 300ms so far seems to produce a reliable result on AC and battery */
>> @@ -288,7 +299,7 @@ struct asus_wmi {
>>  	bool battery_rsoc_available;
>>  
>>  	bool panel_overdrive_available;
>> -	bool mini_led_mode_available;
>> +	u32 mini_led_dev_id;
>>  
>>  	struct hotplug_slot hotplug_slot;
>>  	struct mutex hotplug_lock;
>> @@ -2108,13 +2119,33 @@ static ssize_t mini_led_mode_show(struct device *dev,
>>  				   struct device_attribute *attr, char *buf)
>>  {
>>  	struct asus_wmi *asus = dev_get_drvdata(dev);
>> -	int result;
>> +	u32 value;
>> +	int err;
>>  
>> -	result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
>> -	if (result < 0)
>> -		return result;
>> +	err = asus_wmi_get_devstate(asus, asus->mini_led_dev_id, &value);
>> +	if (err < 0)
>> +		return err;
>> +	value = value & ASUS_MINI_LED_MODE_MASK;
>>  
>> -	return sysfs_emit(buf, "%d\n", result);
>> +	/*
>> +	 * Remap the mode values to match previous generation mini-led. The last gen
>> +	 * WMI 0 == off, while on this version WMI 2 ==off (flipped).
>> +	 */
>> +	if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
>> +		switch (value) {
>> +		case ASUS_MINI_LED_2024_WEAK:
>> +			value = ASUS_MINI_LED_ON;
>> +			break;
>> +		case ASUS_MINI_LED_2024_STRONG:
>> +			value = ASUS_MINI_LED_STRONG_MODE;
>> +			break;
>> +		case ASUS_MINI_LED_2024_OFF:
>> +			value = ASUS_MINI_LED_OFF;
>> +			break;
>> +		}
>> +	}
>> +
>> +	return sysfs_emit(buf, "%d\n", value);
>>  }
>>  
>>  static ssize_t mini_led_mode_store(struct device *dev,
>> @@ -2130,11 +2161,32 @@ static ssize_t mini_led_mode_store(struct device *dev,
>>  	if (result)
>>  		return result;
>>  
>> -	if (mode > 1)
>> +	if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE &&
>> +		mode > ASUS_MINI_LED_ON)
>> +		return -EINVAL;
>> +	if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 &&
>> +		mode > ASUS_MINI_LED_STRONG_MODE)
> 
> The if condition continations should not be indented to the same level as 
> its statement block because it confuses the reader. Hans might be able to 
> fix this while applying though so I'm not sure if it's necessary to send a 
> new version just because of this.

Luke, thank you for the patches.

Ilpo, thank you for all the reviews.

I've fixed this small issue up while merging this and pushed out this
entire series to my review-hans branch.

Regards,

Hans
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
index 8a7e25bde085..ef1ac1a20a71 100644
--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
@@ -126,6 +126,14 @@  Description:
 		Change the mini-LED mode:
 			* 0 - Single-zone,
 			* 1 - Multi-zone
+			* 2 - Multi-zone strong (available on newer generation mini-led)
+
+What:		/sys/devices/platform/<platform>/available_mini_led_mode
+Date:		Apr 2024
+KernelVersion:	6.10
+Contact:	"Luke Jones" <luke@ljones.dev>
+Description:
+		List the available mini-led modes.
 
 What:		/sys/devices/platform/<platform>/ppt_pl1_spl
 Date:		Jun 2023
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 3f07bbf809ef..aa2a3b402e33 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -126,6 +126,17 @@  module_param(fnlock_default, bool, 0444);
 #define ASUS_SCREENPAD_BRIGHT_MAX 255
 #define ASUS_SCREENPAD_BRIGHT_DEFAULT 60
 
+#define ASUS_MINI_LED_MODE_MASK		0x03
+/* Standard modes for devices with only on/off */
+#define ASUS_MINI_LED_OFF		0x00
+#define ASUS_MINI_LED_ON		0x01
+/* New mode on some devices, define here to clarify remapping later */
+#define ASUS_MINI_LED_STRONG_MODE	0x02
+/* New modes for devices with 3 mini-led mode types */
+#define ASUS_MINI_LED_2024_WEAK		0x00
+#define ASUS_MINI_LED_2024_STRONG	0x01
+#define ASUS_MINI_LED_2024_OFF		0x02
+
 /* Controls the power state of the USB0 hub on ROG Ally which input is on */
 #define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE"
 /* 300ms so far seems to produce a reliable result on AC and battery */
@@ -288,7 +299,7 @@  struct asus_wmi {
 	bool battery_rsoc_available;
 
 	bool panel_overdrive_available;
-	bool mini_led_mode_available;
+	u32 mini_led_dev_id;
 
 	struct hotplug_slot hotplug_slot;
 	struct mutex hotplug_lock;
@@ -2108,13 +2119,33 @@  static ssize_t mini_led_mode_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
 	struct asus_wmi *asus = dev_get_drvdata(dev);
-	int result;
+	u32 value;
+	int err;
 
-	result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
-	if (result < 0)
-		return result;
+	err = asus_wmi_get_devstate(asus, asus->mini_led_dev_id, &value);
+	if (err < 0)
+		return err;
+	value = value & ASUS_MINI_LED_MODE_MASK;
 
-	return sysfs_emit(buf, "%d\n", result);
+	/*
+	 * Remap the mode values to match previous generation mini-led. The last gen
+	 * WMI 0 == off, while on this version WMI 2 ==off (flipped).
+	 */
+	if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
+		switch (value) {
+		case ASUS_MINI_LED_2024_WEAK:
+			value = ASUS_MINI_LED_ON;
+			break;
+		case ASUS_MINI_LED_2024_STRONG:
+			value = ASUS_MINI_LED_STRONG_MODE;
+			break;
+		case ASUS_MINI_LED_2024_OFF:
+			value = ASUS_MINI_LED_OFF;
+			break;
+		}
+	}
+
+	return sysfs_emit(buf, "%d\n", value);
 }
 
 static ssize_t mini_led_mode_store(struct device *dev,
@@ -2130,11 +2161,32 @@  static ssize_t mini_led_mode_store(struct device *dev,
 	if (result)
 		return result;
 
-	if (mode > 1)
+	if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE &&
+		mode > ASUS_MINI_LED_ON)
+		return -EINVAL;
+	if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 &&
+		mode > ASUS_MINI_LED_STRONG_MODE)
 		return -EINVAL;
 
-	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MINI_LED_MODE, mode, &result);
+	/*
+	 * Remap the mode values so expected behaviour is the same as the last
+	 * generation of mini-LED with 0 == off, 1 == on.
+	 */
+	if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
+		switch (mode) {
+		case ASUS_MINI_LED_OFF:
+			mode = ASUS_MINI_LED_2024_OFF;
+			break;
+		case ASUS_MINI_LED_ON:
+			mode = ASUS_MINI_LED_2024_WEAK;
+			break;
+		case ASUS_MINI_LED_STRONG_MODE:
+			mode = ASUS_MINI_LED_2024_STRONG;
+			break;
+		}
+	}
 
+	err = asus_wmi_set_devstate(asus->mini_led_dev_id, mode, &result);
 	if (err) {
 		pr_warn("Failed to set mini-LED: %d\n", err);
 		return err;
@@ -2151,6 +2203,23 @@  static ssize_t mini_led_mode_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(mini_led_mode);
 
+static ssize_t available_mini_led_mode_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct asus_wmi *asus = dev_get_drvdata(dev);
+
+	switch (asus->mini_led_dev_id) {
+	case ASUS_WMI_DEVID_MINI_LED_MODE:
+		return sysfs_emit(buf, "0 1\n");
+	case ASUS_WMI_DEVID_MINI_LED_MODE2:
+		return sysfs_emit(buf, "0 1 2\n");
+	}
+
+	return sysfs_emit(buf, "0\n");
+}
+
+static DEVICE_ATTR_RO(available_mini_led_mode);
+
 /* Quirks *********************************************************************/
 
 static void asus_wmi_set_xusb2pr(struct asus_wmi *asus)
@@ -4139,6 +4208,7 @@  static struct attribute *platform_attributes[] = {
 	&dev_attr_nv_temp_target.attr,
 	&dev_attr_panel_od.attr,
 	&dev_attr_mini_led_mode.attr,
+	&dev_attr_available_mini_led_mode.attr,
 	NULL
 };
 
@@ -4191,7 +4261,9 @@  static umode_t asus_sysfs_is_visible(struct kobject *kobj,
 	else if (attr == &dev_attr_panel_od.attr)
 		ok = asus->panel_overdrive_available;
 	else if (attr == &dev_attr_mini_led_mode.attr)
-		ok = asus->mini_led_mode_available;
+		ok = asus->mini_led_dev_id != 0;
+	else if (attr == &dev_attr_available_mini_led_mode.attr)
+		ok = asus->mini_led_dev_id != 0;
 
 	if (devid != -1)
 		ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
@@ -4444,10 +4516,14 @@  static int asus_wmi_add(struct platform_device *pdev)
 	asus->nv_dyn_boost_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_DYN_BOOST);
 	asus->nv_temp_tgt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_THERM_TARGET);
 	asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
-	asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
 	asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE)
 						&& dmi_match(DMI_BOARD_NAME, "RC71L");
 
+	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE))
+		asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
+	else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE2))
+		asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2;
+
 	err = fan_boost_mode_check_present(asus);
 	if (err)
 		goto fail_fan_boost_mode;
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index ab1c7deff118..9cadce10ad9a 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -71,6 +71,7 @@ 
 #define ASUS_WMI_DEVID_LID_FLIP		0x00060062
 #define ASUS_WMI_DEVID_LID_FLIP_ROG	0x00060077
 #define ASUS_WMI_DEVID_MINI_LED_MODE	0x0005001E
+#define ASUS_WMI_DEVID_MINI_LED_MODE2	0x0005002E
 
 /* Storage */
 #define ASUS_WMI_DEVID_CARDREADER	0x00080013