X86 platform drivers
 help / color / mirror / Atom feed
* [PATCH 1/4] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines
@ 2026-02-26  0:31 Werner Sembach
  2026-02-26  0:31 ` [PATCH 2/4] platform/x86/uniwill: Implement USB-C power priority setting Werner Sembach
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Werner Sembach @ 2026-02-26  0:31 UTC (permalink / raw)
  To: Armin Wolf, Hans de Goede, Ilpo Järvinen
  Cc: Werner Sembach, platform-driver-x86, linux-kernel

From: Armin Wolf <W_Armin@gmx.de>

Split hwmon feature define in smaller parts to accommodate for diverse
hardware. You can now specify the presence of a cpu and/or a gpu temp
sensor separately and if one or 2 fans exists.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 drivers/platform/x86/uniwill/uniwill-acpi.c | 68 ++++++++++++++++++---
 1 file changed, 61 insertions(+), 7 deletions(-)

diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 6341dca20b76a..7ab82cf16f388 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -319,8 +319,11 @@
 #define UNIWILL_FEATURE_TOUCHPAD_TOGGLE		BIT(2)
 #define UNIWILL_FEATURE_LIGHTBAR		BIT(3)
 #define UNIWILL_FEATURE_BATTERY			BIT(4)
-#define UNIWILL_FEATURE_HWMON			BIT(5)
-#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL	BIT(6)
+#define UNIWILL_FEATURE_CPU_TEMP		BIT(5)
+#define UNIWILL_FEATURE_GPU_TEMP		BIT(6)
+#define UNIWILL_FEATURE_PRIMARY_FAN		BIT(7)
+#define UNIWILL_FEATURE_SECONDARY_FAN		BIT(8)
+#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL	BIT(9)
 
 struct uniwill_data {
 	struct device *dev;
@@ -427,7 +430,7 @@ static const struct key_entry uniwill_keymap[] = {
 	{ KE_END }
 };
 
-static inline bool uniwill_device_supports(struct uniwill_data *data,
+static inline bool uniwill_device_supports(const struct uniwill_data *data,
 					   unsigned int features)
 {
 	return (data->features & features) == features;
@@ -937,6 +940,48 @@ static const struct attribute_group *uniwill_groups[] = {
 	NULL
 };
 
+static umode_t uniwill_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
+				  int channel)
+{
+	const struct uniwill_data *data = drvdata;
+	unsigned int feature;
+
+	switch (type) {
+	case hwmon_temp:
+		switch (channel) {
+		case 0:
+			feature = UNIWILL_FEATURE_CPU_TEMP;
+			break;
+		case 1:
+			feature = UNIWILL_FEATURE_GPU_TEMP;
+			break;
+		default:
+			return 0;
+		}
+		break;
+	case hwmon_fan:
+	case hwmon_pwm:
+		switch (channel) {
+		case 0:
+			feature = UNIWILL_FEATURE_PRIMARY_FAN;
+			break;
+		case 1:
+			feature = UNIWILL_FEATURE_SECONDARY_FAN;
+			break;
+		default:
+			return 0;
+		}
+		break;
+	default:
+		return 0;
+	}
+
+	if (uniwill_device_supports(data, feature))
+		return 0440;
+
+	return 0;
+}
+
 static int uniwill_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
 			long *val)
 {
@@ -1020,7 +1065,7 @@ static int uniwill_read_string(struct device *dev, enum hwmon_sensor_types type,
 }
 
 static const struct hwmon_ops uniwill_ops = {
-	.visible = 0444,
+	.is_visible = uniwill_is_visible,
 	.read = uniwill_read,
 	.read_string = uniwill_read_string,
 };
@@ -1048,7 +1093,10 @@ static int uniwill_hwmon_init(struct uniwill_data *data)
 {
 	struct device *hdev;
 
-	if (!uniwill_device_supports(data, UNIWILL_FEATURE_HWMON))
+	if (!uniwill_device_supports(data, UNIWILL_FEATURE_CPU_TEMP) &&
+	    !uniwill_device_supports(data, UNIWILL_FEATURE_GPU_TEMP) &&
+	    !uniwill_device_supports(data, UNIWILL_FEATURE_PRIMARY_FAN) &&
+	    !uniwill_device_supports(data, UNIWILL_FEATURE_SECONDARY_FAN))
 		return 0;
 
 	hdev = devm_hwmon_device_register_with_info(data->dev, "uniwill", data,
@@ -1687,7 +1735,10 @@ static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
 		    UNIWILL_FEATURE_SUPER_KEY |
 		    UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
 		    UNIWILL_FEATURE_BATTERY |
-		    UNIWILL_FEATURE_HWMON,
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_GPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN |
+		    UNIWILL_FEATURE_SECONDARY_FAN,
 };
 
 static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
@@ -1696,7 +1747,10 @@ static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
 		    UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
 		    UNIWILL_FEATURE_LIGHTBAR |
 		    UNIWILL_FEATURE_BATTERY |
-		    UNIWILL_FEATURE_HWMON,
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_GPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN |
+		    UNIWILL_FEATURE_SECONDARY_FAN,
 };
 
 static int phxarx1_phxaqf1_probe(struct uniwill_data *data)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/4] platform/x86/uniwill: Implement USB-C power priority setting
  2026-02-26  0:31 [PATCH 1/4] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines Werner Sembach
@ 2026-02-26  0:31 ` Werner Sembach
  2026-02-26  1:11   ` Armin Wolf
  2026-02-26  0:31 ` [PATCH 3/4] platform/x86/uniwill: Apply features across all TUXEDO devices Werner Sembach
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 12+ messages in thread
From: Werner Sembach @ 2026-02-26  0:31 UTC (permalink / raw)
  To: Armin Wolf, Hans de Goede, Ilpo Järvinen
  Cc: Werner Sembach, platform-driver-x86, linux-kernel

On some devices Uniwill offers the option to set the USB-C port to
prioritise charging or performance. This patch exposes this setting to the
userspace via sysfs for all TUXEDO devices supporting it.

Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 drivers/platform/x86/uniwill/uniwill-acpi.c | 99 +++++++++++++++++++--
 1 file changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 7ab82cf16f388..4d9657a3b8c10 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -266,8 +266,8 @@
 #define BATTERY_CHARGE_FULL_OVER_24H	BIT(3)
 #define BATTERY_ERM_STATUS_REACHED	BIT(4)
 
-#define EC_ADDR_CHARGE_PRIO		0x07CC
-#define CHARGING_PERFORMANCE		BIT(7)
+#define EC_ADDR_USB_C_POWER_PRIORITY	0x07CC
+#define USB_C_POWER_PRIORITY		BIT(7)
 
 /* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */
 #define EC_ADDR_LIGHTBAR_BAT_CTRL	0x07E2
@@ -324,6 +324,7 @@
 #define UNIWILL_FEATURE_PRIMARY_FAN		BIT(7)
 #define UNIWILL_FEATURE_SECONDARY_FAN		BIT(8)
 #define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL	BIT(9)
+#define UNIWILL_FEATURE_USB_C_POWER_PRIORITY	BIT(10)
 
 struct uniwill_data {
 	struct device *dev;
@@ -343,6 +344,7 @@ struct uniwill_data {
 	struct mutex input_lock;	/* Protects input sequence during notify */
 	struct input_dev *input_device;
 	struct notifier_block nb;
+	unsigned int last_usb_c_power_priority;
 };
 
 struct uniwill_battery_entry {
@@ -527,6 +529,7 @@ static bool uniwill_writeable_reg(struct device *dev, unsigned int reg)
 	case EC_ADDR_CTGP_DB_CTGP_OFFSET:
 	case EC_ADDR_CTGP_DB_TPP_OFFSET:
 	case EC_ADDR_CTGP_DB_DB_OFFSET:
+	case EC_ADDR_USB_C_POWER_PRIORITY:
 		return true;
 	default:
 		return false;
@@ -565,6 +568,7 @@ static bool uniwill_readable_reg(struct device *dev, unsigned int reg)
 	case EC_ADDR_CTGP_DB_CTGP_OFFSET:
 	case EC_ADDR_CTGP_DB_TPP_OFFSET:
 	case EC_ADDR_CTGP_DB_DB_OFFSET:
+	case EC_ADDR_USB_C_POWER_PRIORITY:
 		return true;
 	default:
 		return false;
@@ -587,6 +591,7 @@ static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
 	case EC_ADDR_TRIGGER:
 	case EC_ADDR_SWITCH_STATUS:
 	case EC_ADDR_CHARGE_CTRL:
+	case EC_ADDR_USB_C_POWER_PRIORITY:
 		return true;
 	default:
 		return false;
@@ -883,6 +888,86 @@ static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
 	return 0;
 }
 
+enum usb_c_power_priority_options {
+	USB_C_POWER_PRIORITY_OPTIONS_CHARGING = 0,
+	USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE,
+};
+
+static const char * const USB_C_POWER_PRIORITY_OPTIONS_TEXT[] = {
+	[USB_C_POWER_PRIORITY_OPTIONS_CHARGING]		= "charging",
+	[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE]	= "performance",
+};
+
+static const u8 USB_C_POWER_PRIORITY_OPTIONS_VALUE[] = {
+	[USB_C_POWER_PRIORITY_OPTIONS_CHARGING]		= 0,
+	[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE]	= USB_C_POWER_PRIORITY,
+};
+
+static ssize_t usb_c_power_priority_store(struct device *dev,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count)
+{
+	struct uniwill_data *data = dev_get_drvdata(dev);
+	unsigned int value;
+	int ret;
+
+	ret = sysfs_match_string(USB_C_POWER_PRIORITY_OPTIONS_TEXT, buf);
+	if (ret < 0)
+		return ret;
+	value = USB_C_POWER_PRIORITY_OPTIONS_VALUE[ret];
+
+	ret = regmap_update_bits(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY,
+				 USB_C_POWER_PRIORITY, value);
+	if (ret < 0)
+		return ret;
+
+	data->last_usb_c_power_priority = value;
+
+	return count;
+}
+
+static ssize_t usb_c_power_priority_show(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct uniwill_data *data = dev_get_drvdata(dev);
+	unsigned int value;
+	ssize_t count = 0;
+	int ret;
+
+	ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value);
+	if (ret < 0)
+		return ret;
+	value &= USB_C_POWER_PRIORITY;
+
+	for (int i = 0; i < ARRAY_SIZE(USB_C_POWER_PRIORITY_OPTIONS_VALUE); ++i) {
+		if (USB_C_POWER_PRIORITY_OPTIONS_VALUE[i] == value)
+			count += sysfs_emit_at(buf, count, "[%s] ",
+					       USB_C_POWER_PRIORITY_OPTIONS_TEXT[i]);
+		else
+			count += sysfs_emit_at(buf, count, "%s ",
+					       USB_C_POWER_PRIORITY_OPTIONS_TEXT[i]);
+	}
+	if (count)
+		buf[count - 1] = '\n';
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(usb_c_power_priority);
+
+static int usb_c_power_priority_restore(struct uniwill_data *data)
+{
+	int ret;
+
+	ret = regmap_update_bits(data->regmap, EC_ADDR_OEM_4, USB_C_POWER_PRIORITY,
+				 data->last_usb_c_power_priority);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
 static struct attribute *uniwill_attrs[] = {
 	/* Keyboard-related */
 	&dev_attr_fn_lock.attr,
@@ -893,6 +978,7 @@ static struct attribute *uniwill_attrs[] = {
 	&dev_attr_breathing_in_suspend.attr,
 	/* Power-management-related */
 	&dev_attr_ctgp_offset.attr,
+	&dev_attr_usb_c_power_priority.attr,
 	NULL
 };
 
@@ -927,6 +1013,11 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
 			return attr->mode;
 	}
 
+	if (attr == &dev_attr_usb_c_power_priority.attr) {
+		if (uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY))
+			return attr->mode;
+	}
+
 	return 0;
 }
 
@@ -1417,9 +1508,7 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
 
 		return NOTIFY_OK;
 	case UNIWILL_OSD_DC_ADAPTER_CHANGED:
-		/* noop for the time being, will change once charging priority
-		 * gets implemented.
-		 */
+		usb_c_power_priority_restore(data);
 
 		return NOTIFY_OK;
 	case UNIWILL_OSD_FN_LOCK:
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/4] platform/x86/uniwill: Apply features across all TUXEDO devices
  2026-02-26  0:31 [PATCH 1/4] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines Werner Sembach
  2026-02-26  0:31 ` [PATCH 2/4] platform/x86/uniwill: Implement USB-C power priority setting Werner Sembach
@ 2026-02-26  0:31 ` Werner Sembach
  2026-02-26  1:15   ` Armin Wolf
  2026-02-26  0:31 ` [PATCH 4/4] Documentation: laptops: Update documentation for uniwill laptops Werner Sembach
  2026-02-26  0:58 ` [PATCH 1/4] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines Armin Wolf
  3 siblings, 1 reply; 12+ messages in thread
From: Werner Sembach @ 2026-02-26  0:31 UTC (permalink / raw)
  To: Armin Wolf, Hans de Goede, Ilpo Järvinen
  Cc: Werner Sembach, platform-driver-x86, linux-kernel

Uses the more fine granular and/or new feature defines to enable more
features across the TUXEDO device lineup.

Also adds features defines that where already present, but not tested until
now.

Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 drivers/platform/x86/uniwill/uniwill-acpi.c | 214 ++++++++++++++------
 1 file changed, 156 insertions(+), 58 deletions(-)

diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 4d9657a3b8c10..88a323241c612 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -110,6 +110,8 @@
 #define EC_ADDR_BAT_CYCLE_COUNT_2	0x04A7
 
 #define EC_ADDR_PROJECT_ID		0x0740
+#define PROJECT_ID_PH4TRX1		0x12
+#define PROJECT_ID_PH6TRX1		0x15
 
 #define EC_ADDR_AP_OEM			0x0741
 #define	ENABLE_MANUAL_CTRL		BIT(0)
@@ -1819,6 +1821,15 @@ static struct platform_driver uniwill_driver = {
 	.shutdown = uniwill_shutdown,
 };
 
+static struct uniwill_device_descriptor lapqc71a_lapqc71b_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_SUPER_KEY |
+		    UNIWILL_FEATURE_BATTERY |
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_GPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN |
+		    UNIWILL_FEATURE_SECONDARY_FAN,
+};
+
 static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
 	.features = UNIWILL_FEATURE_FN_LOCK |
 		    UNIWILL_FEATURE_SUPER_KEY |
@@ -1842,6 +1853,85 @@ static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
 		    UNIWILL_FEATURE_SECONDARY_FAN,
 };
 
+/*
+ * The featuresets below reflect somewhat chronological changes:
+ * 1 -> 2: UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL is added to the EC firmware.
+ * 2 -> 3: UNIWILL_FEATURE_USB_C_POWER_PRIORITY is removed from the EC firmware.
+ * Some devices might divert from this timeline.
+ */
+
+static struct uniwill_device_descriptor tux_featureset_1_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_FN_LOCK |
+		    UNIWILL_FEATURE_SUPER_KEY |
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN |
+		    UNIWILL_FEATURE_SECONDARY_FAN |
+		    UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
+};
+
+static struct uniwill_device_descriptor tux_featureset_1_nvidia_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_FN_LOCK |
+		    UNIWILL_FEATURE_SUPER_KEY |
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_GPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN |
+		    UNIWILL_FEATURE_SECONDARY_FAN |
+		    UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
+};
+
+static struct uniwill_device_descriptor tux_featureset_2_nvidia_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_FN_LOCK |
+		    UNIWILL_FEATURE_SUPER_KEY |
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_GPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN |
+		    UNIWILL_FEATURE_SECONDARY_FAN |
+		    UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL |
+		    UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
+};
+
+static struct uniwill_device_descriptor tux_featureset_3_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_FN_LOCK |
+		    UNIWILL_FEATURE_SUPER_KEY |
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN |
+		    UNIWILL_FEATURE_SECONDARY_FAN,
+};
+
+static struct uniwill_device_descriptor tux_featureset_3_nvidia_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_FN_LOCK |
+		    UNIWILL_FEATURE_SUPER_KEY |
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_GPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN |
+		    UNIWILL_FEATURE_SECONDARY_FAN |
+		    UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL,
+};
+
+static int phxtxx1_probe(struct uniwill_data *data)
+{
+	unsigned int value;
+	int ret;
+
+	ret = regmap_read(data->regmap, EC_ADDR_PROJECT_ID, &value);
+	if (ret < 0)
+		return ret;
+
+	if (value == PROJECT_ID_PH4TRX1 || value == PROJECT_ID_PH6TRX1)
+		data->features |= UNIWILL_FEATURE_SECONDARY_FAN;
+
+	return 0;
+};
+
+static struct uniwill_device_descriptor phxtxx1_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_FN_LOCK |
+		    UNIWILL_FEATURE_SUPER_KEY |
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN |
+		    UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
+	.probe = phxtxx1_probe,
+};
+
 static int phxarx1_phxaqf1_probe(struct uniwill_data *data)
 {
 	unsigned int value;
@@ -1852,37 +1942,45 @@ static int phxarx1_phxaqf1_probe(struct uniwill_data *data)
 		return ret;
 
 	if (value & HAS_GPU)
-		data->features |= UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL;
+		data->features |= UNIWILL_FEATURE_GPU_TEMP |
+				  UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL;
 
 	return 0;
 };
 
 static struct uniwill_device_descriptor phxarx1_phxaqf1_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_FN_LOCK |
+		    UNIWILL_FEATURE_SUPER_KEY |
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN |
+		    UNIWILL_FEATURE_SECONDARY_FAN |
+		    UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
 	.probe = phxarx1_phxaqf1_probe,
 };
 
-static struct uniwill_device_descriptor tux_featureset_1_descriptor __initdata = {
-	.features = UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL,
+static struct uniwill_device_descriptor pf5pu1g_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_FN_LOCK |
+		    UNIWILL_FEATURE_SUPER_KEY |
+		    UNIWILL_FEATURE_CPU_TEMP |
+		    UNIWILL_FEATURE_PRIMARY_FAN,
 };
 
-static struct uniwill_device_descriptor empty_descriptor __initdata = {};
-
 static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 	{
-		.ident = "XMG FUSION 15",
+		.ident = "XMG FUSION 15 (L19)",
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &lapqc71a_lapqc71b_descriptor,
 	},
 	{
-		.ident = "XMG FUSION 15",
+		.ident = "XMG FUSION 15 (L19)",
 		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &lapqc71a_lapqc71b_descriptor,
 	},
 	{
 		.ident = "Intel NUC x15",
@@ -1906,7 +2004,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTxX1"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &phxtxx1_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
@@ -1914,7 +2012,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_2_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
@@ -1930,7 +2028,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_2_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
@@ -1938,7 +2036,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PRX1_PH6PRX1"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
@@ -1946,7 +2044,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_2_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
@@ -1954,7 +2052,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_2_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
@@ -1962,7 +2060,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_3_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore Omnia-Book 15 Gen9",
@@ -1970,7 +2068,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_3_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
@@ -1978,7 +2076,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_3_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
@@ -1986,7 +2084,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_3_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel",
@@ -1994,7 +2092,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_3_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Max 15 Gen10 AMD",
@@ -2002,7 +2100,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
@@ -2010,7 +2108,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6HP45xU"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
@@ -2018,7 +2116,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Max 15 Gen10 Intel",
@@ -2026,7 +2124,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5AR45xS"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO InfinityBook Max 16 Gen10 Intel",
@@ -2034,7 +2132,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR55xU"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 15 Gen1 AMD",
@@ -2042,7 +2140,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 15 Gen1 AMD",
@@ -2050,7 +2148,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 17 Gen1 AMD",
@@ -2058,7 +2156,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 17 Gen1 AMD",
@@ -2066,7 +2164,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 15 Gen1 Intel",
@@ -2074,7 +2172,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I1650TI"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 15 Gen1 Intel",
@@ -2082,7 +2180,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I2060"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 17 Gen1 Intel",
@@ -2090,7 +2188,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I1650TI"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 17 Gen1 Intel",
@@ -2098,7 +2196,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I2060"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Trinity 15 Intel Gen1",
@@ -2106,7 +2204,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1501I"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Trinity 17 Intel Gen1",
@@ -2114,7 +2212,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1701I"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 15/17 Gen2 AMD",
@@ -2122,7 +2220,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_2_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 15/17 Gen2 Intel",
@@ -2130,7 +2228,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_2_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
@@ -2138,7 +2236,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_2_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
@@ -2146,7 +2244,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_2_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
@@ -2154,7 +2252,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris 15 Gen4 Intel",
@@ -2162,7 +2260,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Polaris 15/17 Gen5 AMD",
@@ -2170,7 +2268,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_2_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen5 AMD",
@@ -2178,7 +2276,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
@@ -2186,7 +2284,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
@@ -2194,7 +2292,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6",
@@ -2202,7 +2300,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
@@ -2210,7 +2308,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
@@ -2218,7 +2316,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
@@ -2226,7 +2324,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen7 AMD",
@@ -2234,7 +2332,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
@@ -2242,7 +2340,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
@@ -2250,7 +2348,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
 		},
-		.driver_data = &tux_featureset_1_descriptor,
+		.driver_data = &tux_featureset_3_nvidia_descriptor,
 	},
 	{
 		.ident = "TUXEDO Book BA15 Gen10 AMD",
@@ -2258,7 +2356,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &pf5pu1g_descriptor,
 	},
 	{
 		.ident = "TUXEDO Pulse 14 Gen1 AMD",
@@ -2266,7 +2364,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1401"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_descriptor,
 	},
 	{
 		.ident = "TUXEDO Pulse 15 Gen1 AMD",
@@ -2274,7 +2372,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1501"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_descriptor,
 	},
 	{
 		.ident = "TUXEDO Pulse 15 Gen2 AMD",
@@ -2282,7 +2380,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
 		},
-		.driver_data = &empty_descriptor,
+		.driver_data = &tux_featureset_1_descriptor,
 	},
 	{ }
 };
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/4] Documentation: laptops: Update documentation for uniwill laptops
  2026-02-26  0:31 [PATCH 1/4] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines Werner Sembach
  2026-02-26  0:31 ` [PATCH 2/4] platform/x86/uniwill: Implement USB-C power priority setting Werner Sembach
  2026-02-26  0:31 ` [PATCH 3/4] platform/x86/uniwill: Apply features across all TUXEDO devices Werner Sembach
@ 2026-02-26  0:31 ` Werner Sembach
  2026-02-26  1:17   ` Armin Wolf
  2026-02-26  0:58 ` [PATCH 1/4] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines Armin Wolf
  3 siblings, 1 reply; 12+ messages in thread
From: Werner Sembach @ 2026-02-26  0:31 UTC (permalink / raw)
  To: Armin Wolf, Jonathan Corbet, Shuah Khan
  Cc: Werner Sembach, platform-driver-x86, linux-kernel, linux-doc

Adds short description for two new sysfs entries, ctgp_offset and
usb_c_power_priority, to the documentation of uniwill laptops.

Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 .../ABI/testing/sysfs-driver-uniwill-laptop   | 25 +++++++++++++++++++
 .../admin-guide/laptops/uniwill-laptop.rst    | 12 +++++++++
 2 files changed, 37 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
index 2df70792968f3..55943252f2ab9 100644
--- a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
+++ b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
@@ -51,3 +51,28 @@ Description:
 
 		Reading this file returns the current status of the breathing animation
 		functionality.
+
+What:		/sys/bus/platform/devices/INOU0000:XX/ctgp_offset
+Date:		January 2026
+KernelVersion:	7.0
+Contact:	Werner Sembach <wse@tuxedocomputers.com>
+Description:
+		Allows userspace applications to set the configurable TGP offset on top of the base
+		TGP. Base TGP and max TGP and therefore the max cTGP offset are device specific.
+		Note that setting the maximal cTGP leaves no window open for Dynamic Boost,
+		effectifly disabling that feature for the GPU to always be prioritized.
+
+		Reading this file returns the current configurable TGP offset.
+
+What:		/sys/bus/platform/devices/INOU0000:XX/usb_c_power_priority
+Date:		February 2026
+KernelVersion:	7.1
+Contact:	Werner Sembach <wse@tuxedocomputers.com>
+Description:
+		Allows userspace applications to set USB-C power distribution profile between one
+		that offers a bigger share of the power to the battery and one that offers more of
+		it to the CPU. Writing "charging"/"performance" into this file selects the
+		respective profile.
+
+		Reading this file returns the profile names with the currently active one in
+		brackets.
diff --git a/Documentation/admin-guide/laptops/uniwill-laptop.rst b/Documentation/admin-guide/laptops/uniwill-laptop.rst
index aff5f57a6bd47..c89b8b3756f84 100644
--- a/Documentation/admin-guide/laptops/uniwill-laptop.rst
+++ b/Documentation/admin-guide/laptops/uniwill-laptop.rst
@@ -50,6 +50,10 @@ between 1 and 100 percent are supported.
 Additionally the driver signals the presence of battery charging issues through the standard
 ``health`` power supply sysfs attribute.
 
+It also let you set whether an USB-C power source should prioritise charging the battery or
+delivering immediate power to the cpu. See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for
+details.
+
 Lightbar
 --------
 
@@ -58,3 +62,11 @@ LED class device. The default name of this LED class device is ``uniwill:multico
 
 See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details on how to control the various
 animation modes of the lightbar.
+
+Configurable TGP
+--------
+
+The ``uniwill-laptop`` driver allows to set the configurable TGP for devices with NVIDIA GPUs that
+allow it.
+
+See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/4] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines
  2026-02-26  0:31 [PATCH 1/4] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines Werner Sembach
                   ` (2 preceding siblings ...)
  2026-02-26  0:31 ` [PATCH 4/4] Documentation: laptops: Update documentation for uniwill laptops Werner Sembach
@ 2026-02-26  0:58 ` Armin Wolf
  3 siblings, 0 replies; 12+ messages in thread
From: Armin Wolf @ 2026-02-26  0:58 UTC (permalink / raw)
  To: Werner Sembach, Hans de Goede, Ilpo Järvinen
  Cc: platform-driver-x86, linux-kernel

Am 26.02.26 um 01:31 schrieb Werner Sembach:

> From: Armin Wolf <W_Armin@gmx.de>
>
> Split hwmon feature define in smaller parts to accommodate for diverse
> hardware. You can now specify the presence of a cpu and/or a gpu temp
> sensor separately and if one or 2 fans exists.

Hi,

it would be nice if you could tell people that this series currently only applies
onto review-ilpo-fixes.

> Signed-off-by: Armin Wolf <W_Armin@gmx.de>
> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> ---
>   drivers/platform/x86/uniwill/uniwill-acpi.c | 68 ++++++++++++++++++---
>   1 file changed, 61 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
> index 6341dca20b76a..7ab82cf16f388 100644
> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
> @@ -319,8 +319,11 @@
>   #define UNIWILL_FEATURE_TOUCHPAD_TOGGLE		BIT(2)
>   #define UNIWILL_FEATURE_LIGHTBAR		BIT(3)
>   #define UNIWILL_FEATURE_BATTERY			BIT(4)
> -#define UNIWILL_FEATURE_HWMON			BIT(5)
> -#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL	BIT(6)
> +#define UNIWILL_FEATURE_CPU_TEMP		BIT(5)
> +#define UNIWILL_FEATURE_GPU_TEMP		BIT(6)
> +#define UNIWILL_FEATURE_PRIMARY_FAN		BIT(7)
> +#define UNIWILL_FEATURE_SECONDARY_FAN		BIT(8)
> +#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL	BIT(9)
>   
>   struct uniwill_data {
>   	struct device *dev;
> @@ -427,7 +430,7 @@ static const struct key_entry uniwill_keymap[] = {
>   	{ KE_END }
>   };
>   
> -static inline bool uniwill_device_supports(struct uniwill_data *data,
> +static inline bool uniwill_device_supports(const struct uniwill_data *data,
>   					   unsigned int features)
>   {
>   	return (data->features & features) == features;
> @@ -937,6 +940,48 @@ static const struct attribute_group *uniwill_groups[] = {
>   	NULL
>   };
>   
> +static umode_t uniwill_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
> +				  int channel)
> +{
> +	const struct uniwill_data *data = drvdata;
> +	unsigned int feature;
> +
> +	switch (type) {
> +	case hwmon_temp:
> +		switch (channel) {
> +		case 0:
> +			feature = UNIWILL_FEATURE_CPU_TEMP;
> +			break;
> +		case 1:
> +			feature = UNIWILL_FEATURE_GPU_TEMP;
> +			break;
> +		default:
> +			return 0;
> +		}
> +		break;
> +	case hwmon_fan:
> +	case hwmon_pwm:
> +		switch (channel) {
> +		case 0:
> +			feature = UNIWILL_FEATURE_PRIMARY_FAN;
> +			break;
> +		case 1:
> +			feature = UNIWILL_FEATURE_SECONDARY_FAN;
> +			break;
> +		default:
> +			return 0;
> +		}
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	if (uniwill_device_supports(data, feature))
> +		return 0440;

I just noticed that i made a mistake here, 0444 should be the correct permission setting.

Otherwise, the patch looks good to me.

Thanks,
Armin Wolf

> +
> +	return 0;
> +}
> +
>   static int uniwill_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
>   			long *val)
>   {
> @@ -1020,7 +1065,7 @@ static int uniwill_read_string(struct device *dev, enum hwmon_sensor_types type,
>   }
>   
>   static const struct hwmon_ops uniwill_ops = {
> -	.visible = 0444,
> +	.is_visible = uniwill_is_visible,
>   	.read = uniwill_read,
>   	.read_string = uniwill_read_string,
>   };
> @@ -1048,7 +1093,10 @@ static int uniwill_hwmon_init(struct uniwill_data *data)
>   {
>   	struct device *hdev;
>   
> -	if (!uniwill_device_supports(data, UNIWILL_FEATURE_HWMON))
> +	if (!uniwill_device_supports(data, UNIWILL_FEATURE_CPU_TEMP) &&
> +	    !uniwill_device_supports(data, UNIWILL_FEATURE_GPU_TEMP) &&
> +	    !uniwill_device_supports(data, UNIWILL_FEATURE_PRIMARY_FAN) &&
> +	    !uniwill_device_supports(data, UNIWILL_FEATURE_SECONDARY_FAN))
>   		return 0;
>   
>   	hdev = devm_hwmon_device_register_with_info(data->dev, "uniwill", data,
> @@ -1687,7 +1735,10 @@ static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
>   		    UNIWILL_FEATURE_SUPER_KEY |
>   		    UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
>   		    UNIWILL_FEATURE_BATTERY |
> -		    UNIWILL_FEATURE_HWMON,
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_GPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN |
> +		    UNIWILL_FEATURE_SECONDARY_FAN,
>   };
>   
>   static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
> @@ -1696,7 +1747,10 @@ static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
>   		    UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
>   		    UNIWILL_FEATURE_LIGHTBAR |
>   		    UNIWILL_FEATURE_BATTERY |
> -		    UNIWILL_FEATURE_HWMON,
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_GPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN |
> +		    UNIWILL_FEATURE_SECONDARY_FAN,
>   };
>   
>   static int phxarx1_phxaqf1_probe(struct uniwill_data *data)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/4] platform/x86/uniwill: Implement USB-C power priority setting
  2026-02-26  0:31 ` [PATCH 2/4] platform/x86/uniwill: Implement USB-C power priority setting Werner Sembach
@ 2026-02-26  1:11   ` Armin Wolf
  2026-02-26 15:55     ` Werner Sembach
  0 siblings, 1 reply; 12+ messages in thread
From: Armin Wolf @ 2026-02-26  1:11 UTC (permalink / raw)
  To: Werner Sembach, Hans de Goede, Ilpo Järvinen
  Cc: platform-driver-x86, linux-kernel

Am 26.02.26 um 01:31 schrieb Werner Sembach:

> On some devices Uniwill offers the option to set the USB-C port to
> prioritise charging or performance. This patch exposes this setting to the
> userspace via sysfs for all TUXEDO devices supporting it.
>
> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> ---
>   drivers/platform/x86/uniwill/uniwill-acpi.c | 99 +++++++++++++++++++--
>   1 file changed, 94 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
> index 7ab82cf16f388..4d9657a3b8c10 100644
> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
> @@ -266,8 +266,8 @@
>   #define BATTERY_CHARGE_FULL_OVER_24H	BIT(3)
>   #define BATTERY_ERM_STATUS_REACHED	BIT(4)
>   
> -#define EC_ADDR_CHARGE_PRIO		0x07CC
> -#define CHARGING_PERFORMANCE		BIT(7)
> +#define EC_ADDR_USB_C_POWER_PRIORITY	0x07CC
> +#define USB_C_POWER_PRIORITY		BIT(7)
>   
>   /* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */
>   #define EC_ADDR_LIGHTBAR_BAT_CTRL	0x07E2
> @@ -324,6 +324,7 @@
>   #define UNIWILL_FEATURE_PRIMARY_FAN		BIT(7)
>   #define UNIWILL_FEATURE_SECONDARY_FAN		BIT(8)
>   #define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL	BIT(9)
> +#define UNIWILL_FEATURE_USB_C_POWER_PRIORITY	BIT(10)
>   
>   struct uniwill_data {
>   	struct device *dev;
> @@ -343,6 +344,7 @@ struct uniwill_data {
>   	struct mutex input_lock;	/* Protects input sequence during notify */
>   	struct input_dev *input_device;
>   	struct notifier_block nb;
> +	unsigned int last_usb_c_power_priority;
>   };
>   
>   struct uniwill_battery_entry {
> @@ -527,6 +529,7 @@ static bool uniwill_writeable_reg(struct device *dev, unsigned int reg)
>   	case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>   	case EC_ADDR_CTGP_DB_TPP_OFFSET:
>   	case EC_ADDR_CTGP_DB_DB_OFFSET:
> +	case EC_ADDR_USB_C_POWER_PRIORITY:
>   		return true;
>   	default:
>   		return false;
> @@ -565,6 +568,7 @@ static bool uniwill_readable_reg(struct device *dev, unsigned int reg)
>   	case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>   	case EC_ADDR_CTGP_DB_TPP_OFFSET:
>   	case EC_ADDR_CTGP_DB_DB_OFFSET:
> +	case EC_ADDR_USB_C_POWER_PRIORITY:
>   		return true;
>   	default:
>   		return false;
> @@ -587,6 +591,7 @@ static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
>   	case EC_ADDR_TRIGGER:
>   	case EC_ADDR_SWITCH_STATUS:
>   	case EC_ADDR_CHARGE_CTRL:
> +	case EC_ADDR_USB_C_POWER_PRIORITY:
>   		return true;
>   	default:
>   		return false;
> @@ -883,6 +888,86 @@ static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
>   	return 0;
>   }
>   
> +enum usb_c_power_priority_options {
> +	USB_C_POWER_PRIORITY_OPTIONS_CHARGING = 0,
> +	USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE,
> +};
> +
> +static const char * const USB_C_POWER_PRIORITY_OPTIONS_TEXT[] = {
> +	[USB_C_POWER_PRIORITY_OPTIONS_CHARGING]		= "charging",
> +	[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE]	= "performance",
> +};
> +
> +static const u8 USB_C_POWER_PRIORITY_OPTIONS_VALUE[] = {
> +	[USB_C_POWER_PRIORITY_OPTIONS_CHARGING]		= 0,
> +	[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE]	= USB_C_POWER_PRIORITY,
> +};
> +
> +static ssize_t usb_c_power_priority_store(struct device *dev,
> +					  struct device_attribute *attr,
> +					  const char *buf, size_t count)
> +{
> +	struct uniwill_data *data = dev_get_drvdata(dev);
> +	unsigned int value;
> +	int ret;
> +
> +	ret = sysfs_match_string(USB_C_POWER_PRIORITY_OPTIONS_TEXT, buf);
> +	if (ret < 0)
> +		return ret;

Please put a blank line here.

> +	value = USB_C_POWER_PRIORITY_OPTIONS_VALUE[ret];
> +
> +	ret = regmap_update_bits(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY,
> +				 USB_C_POWER_PRIORITY, value);
> +	if (ret < 0)
> +		return ret;
> +

I think you need a mutex here, so concurrent writes to the charging priority
sysfs attribute are serialized. This mutex would then also protect concurrent
access to data->last_usb_c_power_priority by the event handler.

> +	data->last_usb_c_power_priority = value;
> +
> +	return count;
> +}
> +
> +static ssize_t usb_c_power_priority_show(struct device *dev,
> +					 struct device_attribute *attr,
> +					 char *buf)
> +{
> +	struct uniwill_data *data = dev_get_drvdata(dev);
> +	unsigned int value;
> +	ssize_t count = 0;
> +	int ret;
> +
> +	ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value);
> +	if (ret < 0)
> +		return ret;
> +	value &= USB_C_POWER_PRIORITY;
> +
> +	for (int i = 0; i < ARRAY_SIZE(USB_C_POWER_PRIORITY_OPTIONS_VALUE); ++i) {
> +		if (USB_C_POWER_PRIORITY_OPTIONS_VALUE[i] == value)
> +			count += sysfs_emit_at(buf, count, "[%s] ",
> +					       USB_C_POWER_PRIORITY_OPTIONS_TEXT[i]);
> +		else
> +			count += sysfs_emit_at(buf, count, "%s ",
> +					       USB_C_POWER_PRIORITY_OPTIONS_TEXT[i]);
> +	}
> +	if (count)
> +		buf[count - 1] = '\n';

Please just emit USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE] directly
when the bit is set, and USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_CHARGING] otherwise.
This for loop provides no real value.

> +
> +	return count;
> +}
> +
> +static DEVICE_ATTR_RW(usb_c_power_priority);
> +
> +static int usb_c_power_priority_restore(struct uniwill_data *data)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(data->regmap, EC_ADDR_OEM_4, USB_C_POWER_PRIORITY,
> +				 data->last_usb_c_power_priority);
> +	if (ret < 0)
> +		return ret;
> +
> +	return ret;

Please check the feature flag here before performing the register access. You should also
omit "ret" and instead return the result directly.

Maybe you also need to add the appropriate suspend/resume functions for this?

> +}
> +
>   static struct attribute *uniwill_attrs[] = {
>   	/* Keyboard-related */
>   	&dev_attr_fn_lock.attr,
> @@ -893,6 +978,7 @@ static struct attribute *uniwill_attrs[] = {
>   	&dev_attr_breathing_in_suspend.attr,
>   	/* Power-management-related */
>   	&dev_attr_ctgp_offset.attr,
> +	&dev_attr_usb_c_power_priority.attr,
>   	NULL
>   };
>   
> @@ -927,6 +1013,11 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
>   			return attr->mode;
>   	}
>   
> +	if (attr == &dev_attr_usb_c_power_priority.attr) {
> +		if (uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY))
> +			return attr->mode;
> +	}
> +
>   	return 0;
>   }
>   
> @@ -1417,9 +1508,7 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
>   
>   		return NOTIFY_OK;
>   	case UNIWILL_OSD_DC_ADAPTER_CHANGED:
> -		/* noop for the time being, will change once charging priority
> -		 * gets implemented.
> -		 */
> +		usb_c_power_priority_restore(data);

Please use notifier_from_errno() here.

Thanks,
Armin Wolf

>   
>   		return NOTIFY_OK;
>   	case UNIWILL_OSD_FN_LOCK:

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/4] platform/x86/uniwill: Apply features across all TUXEDO devices
  2026-02-26  0:31 ` [PATCH 3/4] platform/x86/uniwill: Apply features across all TUXEDO devices Werner Sembach
@ 2026-02-26  1:15   ` Armin Wolf
  2026-02-26 20:14     ` Werner Sembach
  0 siblings, 1 reply; 12+ messages in thread
From: Armin Wolf @ 2026-02-26  1:15 UTC (permalink / raw)
  To: Werner Sembach, Hans de Goede, Ilpo Järvinen
  Cc: platform-driver-x86, linux-kernel

Am 26.02.26 um 01:31 schrieb Werner Sembach:

> Uses the more fine granular and/or new feature defines to enable more
> features across the TUXEDO device lineup.
>
> Also adds features defines that where already present, but not tested until
> now.
>
> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> ---
>   drivers/platform/x86/uniwill/uniwill-acpi.c | 214 ++++++++++++++------
>   1 file changed, 156 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
> index 4d9657a3b8c10..88a323241c612 100644
> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
> @@ -110,6 +110,8 @@
>   #define EC_ADDR_BAT_CYCLE_COUNT_2	0x04A7
>   
>   #define EC_ADDR_PROJECT_ID		0x0740
> +#define PROJECT_ID_PH4TRX1		0x12
> +#define PROJECT_ID_PH6TRX1		0x15
>   
>   #define EC_ADDR_AP_OEM			0x0741
>   #define	ENABLE_MANUAL_CTRL		BIT(0)
> @@ -1819,6 +1821,15 @@ static struct platform_driver uniwill_driver = {
>   	.shutdown = uniwill_shutdown,
>   };
>   
> +static struct uniwill_device_descriptor lapqc71a_lapqc71b_descriptor __initdata = {
> +	.features = UNIWILL_FEATURE_SUPER_KEY |
> +		    UNIWILL_FEATURE_BATTERY |
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_GPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN |
> +		    UNIWILL_FEATURE_SECONDARY_FAN,
> +};
> +
>   static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
>   	.features = UNIWILL_FEATURE_FN_LOCK |
>   		    UNIWILL_FEATURE_SUPER_KEY |
> @@ -1842,6 +1853,85 @@ static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
>   		    UNIWILL_FEATURE_SECONDARY_FAN,
>   };
>   
> +/*
> + * The featuresets below reflect somewhat chronological changes:
> + * 1 -> 2: UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL is added to the EC firmware.
> + * 2 -> 3: UNIWILL_FEATURE_USB_C_POWER_PRIORITY is removed from the EC firmware.
> + * Some devices might divert from this timeline.
> + */
> +
> +static struct uniwill_device_descriptor tux_featureset_1_descriptor __initdata = {
> +	.features = UNIWILL_FEATURE_FN_LOCK |
> +		    UNIWILL_FEATURE_SUPER_KEY |
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN |
> +		    UNIWILL_FEATURE_SECONDARY_FAN |
> +		    UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
> +};
> +
> +static struct uniwill_device_descriptor tux_featureset_1_nvidia_descriptor __initdata = {
> +	.features = UNIWILL_FEATURE_FN_LOCK |
> +		    UNIWILL_FEATURE_SUPER_KEY |
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_GPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN |
> +		    UNIWILL_FEATURE_SECONDARY_FAN |
> +		    UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
> +};
> +
> +static struct uniwill_device_descriptor tux_featureset_2_nvidia_descriptor __initdata = {
> +	.features = UNIWILL_FEATURE_FN_LOCK |
> +		    UNIWILL_FEATURE_SUPER_KEY |
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_GPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN |
> +		    UNIWILL_FEATURE_SECONDARY_FAN |
> +		    UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL |
> +		    UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
> +};
> +
> +static struct uniwill_device_descriptor tux_featureset_3_descriptor __initdata = {
> +	.features = UNIWILL_FEATURE_FN_LOCK |
> +		    UNIWILL_FEATURE_SUPER_KEY |
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN |
> +		    UNIWILL_FEATURE_SECONDARY_FAN,
> +};
> +
> +static struct uniwill_device_descriptor tux_featureset_3_nvidia_descriptor __initdata = {
> +	.features = UNIWILL_FEATURE_FN_LOCK |
> +		    UNIWILL_FEATURE_SUPER_KEY |
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_GPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN |
> +		    UNIWILL_FEATURE_SECONDARY_FAN |
> +		    UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL,
> +};
> +
> +static int phxtxx1_probe(struct uniwill_data *data)
> +{
> +	unsigned int value;
> +	int ret;
> +
> +	ret = regmap_read(data->regmap, EC_ADDR_PROJECT_ID, &value);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (value == PROJECT_ID_PH4TRX1 || value == PROJECT_ID_PH6TRX1)
> +		data->features |= UNIWILL_FEATURE_SECONDARY_FAN;
> +
> +	return 0;
> +};
> +
> +static struct uniwill_device_descriptor phxtxx1_descriptor __initdata = {
> +	.features = UNIWILL_FEATURE_FN_LOCK |
> +		    UNIWILL_FEATURE_SUPER_KEY |
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN |
> +		    UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
> +	.probe = phxtxx1_probe,
> +};
> +
>   static int phxarx1_phxaqf1_probe(struct uniwill_data *data)
>   {
>   	unsigned int value;
> @@ -1852,37 +1942,45 @@ static int phxarx1_phxaqf1_probe(struct uniwill_data *data)
>   		return ret;
>   
>   	if (value & HAS_GPU)
> -		data->features |= UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL;
> +		data->features |= UNIWILL_FEATURE_GPU_TEMP |
> +				  UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL;
>   
>   	return 0;
>   };
>   
>   static struct uniwill_device_descriptor phxarx1_phxaqf1_descriptor __initdata = {
> +	.features = UNIWILL_FEATURE_FN_LOCK |
> +		    UNIWILL_FEATURE_SUPER_KEY |
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN |
> +		    UNIWILL_FEATURE_SECONDARY_FAN |
> +		    UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
>   	.probe = phxarx1_phxaqf1_probe,
>   };
>   
> -static struct uniwill_device_descriptor tux_featureset_1_descriptor __initdata = {
> -	.features = UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL,
> +static struct uniwill_device_descriptor pf5pu1g_descriptor __initdata = {
> +	.features = UNIWILL_FEATURE_FN_LOCK |
> +		    UNIWILL_FEATURE_SUPER_KEY |
> +		    UNIWILL_FEATURE_CPU_TEMP |
> +		    UNIWILL_FEATURE_PRIMARY_FAN,
>   };
>   
> -static struct uniwill_device_descriptor empty_descriptor __initdata = {};
> -
>   static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   	{
> -		.ident = "XMG FUSION 15",
> +		.ident = "XMG FUSION 15 (L19)",
>   		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &lapqc71a_lapqc71b_descriptor,
>   	},
>   	{
> -		.ident = "XMG FUSION 15",
> +		.ident = "XMG FUSION 15 (L19)",
>   		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &lapqc71a_lapqc71b_descriptor,
>   	},

Was choosing "TUXEDO" as the DMI_SYS_VENDOR a mistake made when adding said entries?
If yes then please fix them with a separate commit and add the appropriate Fixes:
tag so this commit can be picked by the stable kernels.

Other than that:
Reviewed-by: Armin Wolf <W_Armin@gmx.de>

>   	{
>   		.ident = "Intel NUC x15",
> @@ -1906,7 +2004,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTxX1"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &phxtxx1_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
> @@ -1914,7 +2012,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_2_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
> @@ -1930,7 +2028,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_2_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
> @@ -1938,7 +2036,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PRX1_PH6PRX1"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
> @@ -1946,7 +2044,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_2_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
> @@ -1954,7 +2052,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_2_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
> @@ -1962,7 +2060,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_3_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore Omnia-Book 15 Gen9",
> @@ -1970,7 +2068,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_3_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
> @@ -1978,7 +2076,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_3_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
> @@ -1986,7 +2084,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_3_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel",
> @@ -1994,7 +2092,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_3_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Max 15 Gen10 AMD",
> @@ -2002,7 +2100,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
> @@ -2010,7 +2108,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6HP45xU"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
> @@ -2018,7 +2116,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Max 15 Gen10 Intel",
> @@ -2026,7 +2124,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5AR45xS"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Max 16 Gen10 Intel",
> @@ -2034,7 +2132,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR55xU"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 15 Gen1 AMD",
> @@ -2042,7 +2140,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 15 Gen1 AMD",
> @@ -2050,7 +2148,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 17 Gen1 AMD",
> @@ -2058,7 +2156,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 17 Gen1 AMD",
> @@ -2066,7 +2164,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 15 Gen1 Intel",
> @@ -2074,7 +2172,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I1650TI"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 15 Gen1 Intel",
> @@ -2082,7 +2180,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I2060"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 17 Gen1 Intel",
> @@ -2090,7 +2188,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I1650TI"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 17 Gen1 Intel",
> @@ -2098,7 +2196,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I2060"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Trinity 15 Intel Gen1",
> @@ -2106,7 +2204,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1501I"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Trinity 17 Intel Gen1",
> @@ -2114,7 +2212,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1701I"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 15/17 Gen2 AMD",
> @@ -2122,7 +2220,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_2_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 15/17 Gen2 Intel",
> @@ -2130,7 +2228,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_2_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
> @@ -2138,7 +2236,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_2_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
> @@ -2146,7 +2244,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_2_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
> @@ -2154,7 +2252,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 15 Gen4 Intel",
> @@ -2162,7 +2260,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 15/17 Gen5 AMD",
> @@ -2170,7 +2268,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_2_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen5 AMD",
> @@ -2178,7 +2276,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
> @@ -2186,7 +2284,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
> @@ -2194,7 +2292,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6",
> @@ -2202,7 +2300,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
> @@ -2210,7 +2308,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
> @@ -2218,7 +2316,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
> @@ -2226,7 +2324,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen7 AMD",
> @@ -2234,7 +2332,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
> @@ -2242,7 +2340,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
> @@ -2250,7 +2348,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
>   		},
> -		.driver_data = &tux_featureset_1_descriptor,
> +		.driver_data = &tux_featureset_3_nvidia_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Book BA15 Gen10 AMD",
> @@ -2258,7 +2356,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &pf5pu1g_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Pulse 14 Gen1 AMD",
> @@ -2266,7 +2364,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1401"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Pulse 15 Gen1 AMD",
> @@ -2274,7 +2372,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1501"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_descriptor,
>   	},
>   	{
>   		.ident = "TUXEDO Pulse 15 Gen2 AMD",
> @@ -2282,7 +2380,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
>   		},
> -		.driver_data = &empty_descriptor,
> +		.driver_data = &tux_featureset_1_descriptor,
>   	},
>   	{ }
>   };

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/4] Documentation: laptops: Update documentation for uniwill laptops
  2026-02-26  0:31 ` [PATCH 4/4] Documentation: laptops: Update documentation for uniwill laptops Werner Sembach
@ 2026-02-26  1:17   ` Armin Wolf
  0 siblings, 0 replies; 12+ messages in thread
From: Armin Wolf @ 2026-02-26  1:17 UTC (permalink / raw)
  To: Werner Sembach, Jonathan Corbet, Shuah Khan
  Cc: platform-driver-x86, linux-kernel, linux-doc

Am 26.02.26 um 01:31 schrieb Werner Sembach:

> Adds short description for two new sysfs entries, ctgp_offset and
> usb_c_power_priority, to the documentation of uniwill laptops.
>
> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> ---
>   .../ABI/testing/sysfs-driver-uniwill-laptop   | 25 +++++++++++++++++++
>   .../admin-guide/laptops/uniwill-laptop.rst    | 12 +++++++++
>   2 files changed, 37 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
> index 2df70792968f3..55943252f2ab9 100644
> --- a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
> +++ b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
> @@ -51,3 +51,28 @@ Description:
>   
>   		Reading this file returns the current status of the breathing animation
>   		functionality.
> +
> +What:		/sys/bus/platform/devices/INOU0000:XX/ctgp_offset
> +Date:		January 2026
> +KernelVersion:	7.0
> +Contact:	Werner Sembach <wse@tuxedocomputers.com>
> +Description:
> +		Allows userspace applications to set the configurable TGP offset on top of the base
> +		TGP. Base TGP and max TGP and therefore the max cTGP offset are device specific.
> +		Note that setting the maximal cTGP leaves no window open for Dynamic Boost,
> +		effectifly disabling that feature for the GPU to always be prioritized.
> +
> +		Reading this file returns the current configurable TGP offset.
> +
> +What:		/sys/bus/platform/devices/INOU0000:XX/usb_c_power_priority
> +Date:		February 2026
> +KernelVersion:	7.1
> +Contact:	Werner Sembach <wse@tuxedocomputers.com>
> +Description:
> +		Allows userspace applications to set USB-C power distribution profile between one
> +		that offers a bigger share of the power to the battery and one that offers more of
> +		it to the CPU. Writing "charging"/"performance" into this file selects the
> +		respective profile.
> +
> +		Reading this file returns the profile names with the currently active one in
> +		brackets.
> diff --git a/Documentation/admin-guide/laptops/uniwill-laptop.rst b/Documentation/admin-guide/laptops/uniwill-laptop.rst
> index aff5f57a6bd47..c89b8b3756f84 100644
> --- a/Documentation/admin-guide/laptops/uniwill-laptop.rst
> +++ b/Documentation/admin-guide/laptops/uniwill-laptop.rst
> @@ -50,6 +50,10 @@ between 1 and 100 percent are supported.
>   Additionally the driver signals the presence of battery charging issues through the standard
>   ``health`` power supply sysfs attribute.
>   
> +It also let you set whether an USB-C power source should prioritise charging the battery or

set -> choose

Other than that:
Reviewed-by: Armin Wolf <W_Armin@gmx.de>

> +delivering immediate power to the cpu. See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for
> +details.
> +
>   Lightbar
>   --------
>   
> @@ -58,3 +62,11 @@ LED class device. The default name of this LED class device is ``uniwill:multico
>   
>   See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details on how to control the various
>   animation modes of the lightbar.
> +
> +Configurable TGP
> +--------
> +
> +The ``uniwill-laptop`` driver allows to set the configurable TGP for devices with NVIDIA GPUs that
> +allow it.
> +
> +See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/4] platform/x86/uniwill: Implement USB-C power priority setting
  2026-02-26  1:11   ` Armin Wolf
@ 2026-02-26 15:55     ` Werner Sembach
  2026-02-27  9:27       ` Armin Wolf
  0 siblings, 1 reply; 12+ messages in thread
From: Werner Sembach @ 2026-02-26 15:55 UTC (permalink / raw)
  To: Armin Wolf, Hans de Goede, Ilpo Järvinen
  Cc: platform-driver-x86, linux-kernel


Am 26.02.26 um 02:11 schrieb Armin Wolf:
> Am 26.02.26 um 01:31 schrieb Werner Sembach:
>
>> On some devices Uniwill offers the option to set the USB-C port to
>> prioritise charging or performance. This patch exposes this setting to the
>> userspace via sysfs for all TUXEDO devices supporting it.
>>
>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>> ---
>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 99 +++++++++++++++++++--
>>   1 file changed, 94 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> index 7ab82cf16f388..4d9657a3b8c10 100644
>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> @@ -266,8 +266,8 @@
>>   #define BATTERY_CHARGE_FULL_OVER_24H    BIT(3)
>>   #define BATTERY_ERM_STATUS_REACHED    BIT(4)
>>   -#define EC_ADDR_CHARGE_PRIO        0x07CC
>> -#define CHARGING_PERFORMANCE        BIT(7)
>> +#define EC_ADDR_USB_C_POWER_PRIORITY    0x07CC
>> +#define USB_C_POWER_PRIORITY        BIT(7)
>>     /* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */
>>   #define EC_ADDR_LIGHTBAR_BAT_CTRL    0x07E2
>> @@ -324,6 +324,7 @@
>>   #define UNIWILL_FEATURE_PRIMARY_FAN        BIT(7)
>>   #define UNIWILL_FEATURE_SECONDARY_FAN        BIT(8)
>>   #define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL    BIT(9)
>> +#define UNIWILL_FEATURE_USB_C_POWER_PRIORITY    BIT(10)
>>     struct uniwill_data {
>>       struct device *dev;
>> @@ -343,6 +344,7 @@ struct uniwill_data {
>>       struct mutex input_lock;    /* Protects input sequence during notify */
>>       struct input_dev *input_device;
>>       struct notifier_block nb;
>> +    unsigned int last_usb_c_power_priority;
>>   };
>>     struct uniwill_battery_entry {
>> @@ -527,6 +529,7 @@ static bool uniwill_writeable_reg(struct device *dev, 
>> unsigned int reg)
>>       case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>       case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>       case EC_ADDR_CTGP_DB_DB_OFFSET:
>> +    case EC_ADDR_USB_C_POWER_PRIORITY:
>>           return true;
>>       default:
>>           return false;
>> @@ -565,6 +568,7 @@ static bool uniwill_readable_reg(struct device *dev, 
>> unsigned int reg)
>>       case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>       case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>       case EC_ADDR_CTGP_DB_DB_OFFSET:
>> +    case EC_ADDR_USB_C_POWER_PRIORITY:
>>           return true;
>>       default:
>>           return false;
>> @@ -587,6 +591,7 @@ static bool uniwill_volatile_reg(struct device *dev, 
>> unsigned int reg)
>>       case EC_ADDR_TRIGGER:
>>       case EC_ADDR_SWITCH_STATUS:
>>       case EC_ADDR_CHARGE_CTRL:
>> +    case EC_ADDR_USB_C_POWER_PRIORITY:
>>           return true;
>>       default:
>>           return false;
>> @@ -883,6 +888,86 @@ static int uniwill_nvidia_ctgp_init(struct uniwill_data 
>> *data)
>>       return 0;
>>   }
>>   +enum usb_c_power_priority_options {
>> +    USB_C_POWER_PRIORITY_OPTIONS_CHARGING = 0,
>> +    USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE,
>> +};
>> +
>> +static const char * const USB_C_POWER_PRIORITY_OPTIONS_TEXT[] = {
>> +    [USB_C_POWER_PRIORITY_OPTIONS_CHARGING]        = "charging",
>> +    [USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE]    = "performance",
>> +};
>> +
>> +static const u8 USB_C_POWER_PRIORITY_OPTIONS_VALUE[] = {
>> +    [USB_C_POWER_PRIORITY_OPTIONS_CHARGING]        = 0,
>> +    [USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE]    = USB_C_POWER_PRIORITY,
>> +};
>> +
>> +static ssize_t usb_c_power_priority_store(struct device *dev,
>> +                      struct device_attribute *attr,
>> +                      const char *buf, size_t count)
>> +{
>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>> +    unsigned int value;
>> +    int ret;
>> +
>> +    ret = sysfs_match_string(USB_C_POWER_PRIORITY_OPTIONS_TEXT, buf);
>> +    if (ret < 0)
>> +        return ret;
>
> Please put a blank line here.
ack
>
>> +    value = USB_C_POWER_PRIORITY_OPTIONS_VALUE[ret];
>> +
>> +    ret = regmap_update_bits(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY,
>> +                 USB_C_POWER_PRIORITY, value);
>> +    if (ret < 0)
>> +        return ret;
>> +
>
> I think you need a mutex here, so concurrent writes to the charging priority
> sysfs attribute are serialized. This mutex would then also protect concurrent
> access to data->last_usb_c_power_priority by the event handler.
ack
>
>> +    data->last_usb_c_power_priority = value;
>> +
>> +    return count;
>> +}
>> +
>> +static ssize_t usb_c_power_priority_show(struct device *dev,
>> +                     struct device_attribute *attr,
>> +                     char *buf)
>> +{
>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>> +    unsigned int value;
>> +    ssize_t count = 0;
>> +    int ret;
>> +
>> +    ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value);
>> +    if (ret < 0)
>> +        return ret;
>> +    value &= USB_C_POWER_PRIORITY;
>> +
>> +    for (int i = 0; i < ARRAY_SIZE(USB_C_POWER_PRIORITY_OPTIONS_VALUE); ++i) {
>> +        if (USB_C_POWER_PRIORITY_OPTIONS_VALUE[i] == value)
>> +            count += sysfs_emit_at(buf, count, "[%s] ",
>> + USB_C_POWER_PRIORITY_OPTIONS_TEXT[i]);
>> +        else
>> +            count += sysfs_emit_at(buf, count, "%s ",
>> + USB_C_POWER_PRIORITY_OPTIONS_TEXT[i]);
>> +    }
>> +    if (count)
>> +        buf[count - 1] = '\n';
>
> Please just emit 
> USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE] 
> directly
> when the bit is set, and 
> USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_CHARGING] 
> otherwise.
> This for loop provides no real value.

It does give context on which values are available. It it is otherwise not 
easily deduceable without referring to the documentation.

Also USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE] 
is BIT(7) which is a kinda random number when expressed as an integer.

>
>> +
>> +    return count;
>> +}
>> +
>> +static DEVICE_ATTR_RW(usb_c_power_priority);
>> +
>> +static int usb_c_power_priority_restore(struct uniwill_data *data)
>> +{
>> +    int ret;
>> +
>> +    ret = regmap_update_bits(data->regmap, EC_ADDR_OEM_4, USB_C_POWER_PRIORITY,
>> +                 data->last_usb_c_power_priority);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    return ret;
>
> Please check the feature flag here before performing the register access. You 
> should also
> omit "ret" and instead return the result directly.
ack
>
> Maybe you also need to add the appropriate suspend/resume functions for this?
tuxedo-drivers doesn't have it for this, so it's probably not necessary
>
>> +}
>> +
>>   static struct attribute *uniwill_attrs[] = {
>>       /* Keyboard-related */
>>       &dev_attr_fn_lock.attr,
>> @@ -893,6 +978,7 @@ static struct attribute *uniwill_attrs[] = {
>>       &dev_attr_breathing_in_suspend.attr,
>>       /* Power-management-related */
>>       &dev_attr_ctgp_offset.attr,
>> +    &dev_attr_usb_c_power_priority.attr,
>>       NULL
>>   };
>>   @@ -927,6 +1013,11 @@ static umode_t uniwill_attr_is_visible(struct kobject 
>> *kobj, struct attribute *a
>>               return attr->mode;
>>       }
>>   +    if (attr == &dev_attr_usb_c_power_priority.attr) {
>> +        if (uniwill_device_supports(data, 
>> UNIWILL_FEATURE_USB_C_POWER_PRIORITY))
>> +            return attr->mode;
>> +    }
>> +
>>       return 0;
>>   }
>>   @@ -1417,9 +1508,7 @@ static int uniwill_notifier_call(struct 
>> notifier_block *nb, unsigned long action
>>             return NOTIFY_OK;
>>       case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>> -        /* noop for the time being, will change once charging priority
>> -         * gets implemented.
>> -         */
>> +        usb_c_power_priority_restore(data);
>
> Please use notifier_from_errno() here.
ack
>
> Thanks,
> Armin Wolf
>
>>             return NOTIFY_OK;
>>       case UNIWILL_OSD_FN_LOCK:

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/4] platform/x86/uniwill: Apply features across all TUXEDO devices
  2026-02-26  1:15   ` Armin Wolf
@ 2026-02-26 20:14     ` Werner Sembach
  0 siblings, 0 replies; 12+ messages in thread
From: Werner Sembach @ 2026-02-26 20:14 UTC (permalink / raw)
  To: Armin Wolf, Hans de Goede, Ilpo Järvinen
  Cc: platform-driver-x86, linux-kernel


Am 26.02.26 um 02:15 schrieb Armin Wolf:
> Am 26.02.26 um 01:31 schrieb Werner Sembach:
>
>> Uses the more fine granular and/or new feature defines to enable more
>> features across the TUXEDO device lineup.
>>
>> Also adds features defines that where already present, but not tested until
>> now.
>>
>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>> ---
>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 214 ++++++++++++++------
>>   1 file changed, 156 insertions(+), 58 deletions(-)
>>
>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> index 4d9657a3b8c10..88a323241c612 100644
>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> @@ -110,6 +110,8 @@
>>   #define EC_ADDR_BAT_CYCLE_COUNT_2    0x04A7
>>     #define EC_ADDR_PROJECT_ID        0x0740
>> +#define PROJECT_ID_PH4TRX1        0x12
>> +#define PROJECT_ID_PH6TRX1        0x15
>>     #define EC_ADDR_AP_OEM            0x0741
>>   #define    ENABLE_MANUAL_CTRL        BIT(0)
>> @@ -1819,6 +1821,15 @@ static struct platform_driver uniwill_driver = {
>>       .shutdown = uniwill_shutdown,
>>   };
>>   +static struct uniwill_device_descriptor lapqc71a_lapqc71b_descriptor 
>> __initdata = {
>> +    .features = UNIWILL_FEATURE_SUPER_KEY |
>> +            UNIWILL_FEATURE_BATTERY |
>> +            UNIWILL_FEATURE_CPU_TEMP |
>> +            UNIWILL_FEATURE_GPU_TEMP |
>> +            UNIWILL_FEATURE_PRIMARY_FAN |
>> +            UNIWILL_FEATURE_SECONDARY_FAN,
>> +};
>> +
>>   static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
>>       .features = UNIWILL_FEATURE_FN_LOCK |
>>               UNIWILL_FEATURE_SUPER_KEY |
>> @@ -1842,6 +1853,85 @@ static struct uniwill_device_descriptor 
>> lapkc71f_descriptor __initdata = {
>>               UNIWILL_FEATURE_SECONDARY_FAN,
>>   };
>>   +/*
>> + * The featuresets below reflect somewhat chronological changes:
>> + * 1 -> 2: UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL is added to the EC firmware.
>> + * 2 -> 3: UNIWILL_FEATURE_USB_C_POWER_PRIORITY is removed from the EC 
>> firmware.
>> + * Some devices might divert from this timeline.
>> + */
>> +
>> +static struct uniwill_device_descriptor tux_featureset_1_descriptor 
>> __initdata = {
>> +    .features = UNIWILL_FEATURE_FN_LOCK |
>> +            UNIWILL_FEATURE_SUPER_KEY |
>> +            UNIWILL_FEATURE_CPU_TEMP |
>> +            UNIWILL_FEATURE_PRIMARY_FAN |
>> +            UNIWILL_FEATURE_SECONDARY_FAN |
>> +            UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
>> +};
>> +
>> +static struct uniwill_device_descriptor tux_featureset_1_nvidia_descriptor 
>> __initdata = {
>> +    .features = UNIWILL_FEATURE_FN_LOCK |
>> +            UNIWILL_FEATURE_SUPER_KEY |
>> +            UNIWILL_FEATURE_CPU_TEMP |
>> +            UNIWILL_FEATURE_GPU_TEMP |
>> +            UNIWILL_FEATURE_PRIMARY_FAN |
>> +            UNIWILL_FEATURE_SECONDARY_FAN |
>> +            UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
>> +};
>> +
>> +static struct uniwill_device_descriptor tux_featureset_2_nvidia_descriptor 
>> __initdata = {
>> +    .features = UNIWILL_FEATURE_FN_LOCK |
>> +            UNIWILL_FEATURE_SUPER_KEY |
>> +            UNIWILL_FEATURE_CPU_TEMP |
>> +            UNIWILL_FEATURE_GPU_TEMP |
>> +            UNIWILL_FEATURE_PRIMARY_FAN |
>> +            UNIWILL_FEATURE_SECONDARY_FAN |
>> +            UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL |
>> +            UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
>> +};
>> +
>> +static struct uniwill_device_descriptor tux_featureset_3_descriptor 
>> __initdata = {
>> +    .features = UNIWILL_FEATURE_FN_LOCK |
>> +            UNIWILL_FEATURE_SUPER_KEY |
>> +            UNIWILL_FEATURE_CPU_TEMP |
>> +            UNIWILL_FEATURE_PRIMARY_FAN |
>> +            UNIWILL_FEATURE_SECONDARY_FAN,
>> +};
>> +
>> +static struct uniwill_device_descriptor tux_featureset_3_nvidia_descriptor 
>> __initdata = {
>> +    .features = UNIWILL_FEATURE_FN_LOCK |
>> +            UNIWILL_FEATURE_SUPER_KEY |
>> +            UNIWILL_FEATURE_CPU_TEMP |
>> +            UNIWILL_FEATURE_GPU_TEMP |
>> +            UNIWILL_FEATURE_PRIMARY_FAN |
>> +            UNIWILL_FEATURE_SECONDARY_FAN |
>> +            UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL,
>> +};
>> +
>> +static int phxtxx1_probe(struct uniwill_data *data)
>> +{
>> +    unsigned int value;
>> +    int ret;
>> +
>> +    ret = regmap_read(data->regmap, EC_ADDR_PROJECT_ID, &value);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    if (value == PROJECT_ID_PH4TRX1 || value == PROJECT_ID_PH6TRX1)
>> +        data->features |= UNIWILL_FEATURE_SECONDARY_FAN;
>> +
>> +    return 0;
>> +};
>> +
>> +static struct uniwill_device_descriptor phxtxx1_descriptor __initdata = {
>> +    .features = UNIWILL_FEATURE_FN_LOCK |
>> +            UNIWILL_FEATURE_SUPER_KEY |
>> +            UNIWILL_FEATURE_CPU_TEMP |
>> +            UNIWILL_FEATURE_PRIMARY_FAN |
>> +            UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
>> +    .probe = phxtxx1_probe,
>> +};
>> +
>>   static int phxarx1_phxaqf1_probe(struct uniwill_data *data)
>>   {
>>       unsigned int value;
>> @@ -1852,37 +1942,45 @@ static int phxarx1_phxaqf1_probe(struct uniwill_data 
>> *data)
>>           return ret;
>>         if (value & HAS_GPU)
>> -        data->features |= UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL;
>> +        data->features |= UNIWILL_FEATURE_GPU_TEMP |
>> +                  UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL;
>>         return 0;
>>   };
>>     static struct uniwill_device_descriptor phxarx1_phxaqf1_descriptor 
>> __initdata = {
>> +    .features = UNIWILL_FEATURE_FN_LOCK |
>> +            UNIWILL_FEATURE_SUPER_KEY |
>> +            UNIWILL_FEATURE_CPU_TEMP |
>> +            UNIWILL_FEATURE_PRIMARY_FAN |
>> +            UNIWILL_FEATURE_SECONDARY_FAN |
>> +            UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
>>       .probe = phxarx1_phxaqf1_probe,
>>   };
>>   -static struct uniwill_device_descriptor tux_featureset_1_descriptor 
>> __initdata = {
>> -    .features = UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL,
>> +static struct uniwill_device_descriptor pf5pu1g_descriptor __initdata = {
>> +    .features = UNIWILL_FEATURE_FN_LOCK |
>> +            UNIWILL_FEATURE_SUPER_KEY |
>> +            UNIWILL_FEATURE_CPU_TEMP |
>> +            UNIWILL_FEATURE_PRIMARY_FAN,
>>   };
>>   -static struct uniwill_device_descriptor empty_descriptor __initdata = {};
>> -
>>   static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>>       {
>> -        .ident = "XMG FUSION 15",
>> +        .ident = "XMG FUSION 15 (L19)",
>>           .matches = {
>> -            DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
>> +            DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &lapqc71a_lapqc71b_descriptor,
>>       },
>>       {
>> -        .ident = "XMG FUSION 15",
>> +        .ident = "XMG FUSION 15 (L19)",
>>           .matches = {
>> -            DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
>> +            DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &lapqc71a_lapqc71b_descriptor,
>>       },
>
> Was choosing "TUXEDO" as the DMI_SYS_VENDOR a mistake made when adding said 
> entries?
> If yes then please fix them with a separate commit and add the appropriate Fixes:
> tag so this commit can be picked by the stable kernels.

More the other way around was a mistake. Thing is the first XMG Fusion was sold 
both by XMG and TUXEDO afaik. It was a cooperation back in the day getting some 
attention to linux for Windows gamers or so. That's why this one XMG device is 
officially supported by us.

TBH I don't know if the seller was reflected in the DMI strings, at least the 
one test device i have at hand has TUXEDO as the system vendor.

If one can confirm that the other string set exists also he*she can then just 
add it I guess?

>
> Other than that:
> Reviewed-by: Armin Wolf <W_Armin@gmx.de>
>
>>       {
>>           .ident = "Intel NUC x15",
>> @@ -1906,7 +2004,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTxX1"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &phxtxx1_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
>> @@ -1914,7 +2012,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_2_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
>> @@ -1930,7 +2028,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_2_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore 
>> Omnia-Book Pro Gen 8",
>> @@ -1938,7 +2036,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PRX1_PH6PRX1"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14 Gen8 Intel/Commodore 
>> Omnia-Book Pro Gen 8",
>> @@ -1946,7 +2044,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_2_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
>> @@ -1954,7 +2052,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_2_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
>> @@ -1962,7 +2060,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_3_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore 
>> Omnia-Book 15 Gen9",
>> @@ -1970,7 +2068,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_3_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
>> @@ -1978,7 +2076,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_3_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
>> @@ -1986,7 +2084,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_3_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel",
>> @@ -1994,7 +2092,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_3_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Max 15 Gen10 AMD",
>> @@ -2002,7 +2100,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
>> @@ -2010,7 +2108,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6HP45xU"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
>> @@ -2018,7 +2116,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Max 15 Gen10 Intel",
>> @@ -2026,7 +2124,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5AR45xS"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Max 16 Gen10 Intel",
>> @@ -2034,7 +2132,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR55xU"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 15 Gen1 AMD",
>> @@ -2042,7 +2140,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 15 Gen1 AMD",
>> @@ -2050,7 +2148,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 17 Gen1 AMD",
>> @@ -2058,7 +2156,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 17 Gen1 AMD",
>> @@ -2066,7 +2164,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 15 Gen1 Intel",
>> @@ -2074,7 +2172,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I1650TI"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 15 Gen1 Intel",
>> @@ -2082,7 +2180,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I2060"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 17 Gen1 Intel",
>> @@ -2090,7 +2188,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I1650TI"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 17 Gen1 Intel",
>> @@ -2098,7 +2196,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I2060"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Trinity 15 Intel Gen1",
>> @@ -2106,7 +2204,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1501I"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Trinity 17 Intel Gen1",
>> @@ -2114,7 +2212,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1701I"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 15/17 Gen2 AMD",
>> @@ -2122,7 +2220,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_2_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 15/17 Gen2 Intel",
>> @@ -2130,7 +2228,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_2_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
>> @@ -2138,7 +2236,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_2_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
>> @@ -2146,7 +2244,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_2_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
>> @@ -2154,7 +2252,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 15 Gen4 Intel",
>> @@ -2162,7 +2260,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 15/17 Gen5 AMD",
>> @@ -2170,7 +2268,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_2_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen5 AMD",
>> @@ -2178,7 +2276,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
>> @@ -2186,7 +2284,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
>> @@ -2194,7 +2292,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 
>> 15 Gen6",
>> @@ -2202,7 +2300,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
>> @@ -2210,7 +2308,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
>> @@ -2218,7 +2316,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
>> @@ -2226,7 +2324,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen7 AMD",
>> @@ -2234,7 +2332,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>> @@ -2242,7 +2340,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>> @@ -2250,7 +2348,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
>>           },
>> -        .driver_data = &tux_featureset_1_descriptor,
>> +        .driver_data = &tux_featureset_3_nvidia_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Book BA15 Gen10 AMD",
>> @@ -2258,7 +2356,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &pf5pu1g_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Pulse 14 Gen1 AMD",
>> @@ -2266,7 +2364,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1401"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Pulse 15 Gen1 AMD",
>> @@ -2274,7 +2372,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1501"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_descriptor,
>>       },
>>       {
>>           .ident = "TUXEDO Pulse 15 Gen2 AMD",
>> @@ -2282,7 +2380,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
>>           },
>> -        .driver_data = &empty_descriptor,
>> +        .driver_data = &tux_featureset_1_descriptor,
>>       },
>>       { }
>>   };

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/4] platform/x86/uniwill: Implement USB-C power priority setting
  2026-02-26 15:55     ` Werner Sembach
@ 2026-02-27  9:27       ` Armin Wolf
  2026-02-27 18:40         ` Werner Sembach
  0 siblings, 1 reply; 12+ messages in thread
From: Armin Wolf @ 2026-02-27  9:27 UTC (permalink / raw)
  To: Werner Sembach, Hans de Goede, Ilpo Järvinen
  Cc: platform-driver-x86, linux-kernel

Am 26.02.26 um 16:55 schrieb Werner Sembach:

>
> Am 26.02.26 um 02:11 schrieb Armin Wolf:
>> Am 26.02.26 um 01:31 schrieb Werner Sembach:
>>
>>> On some devices Uniwill offers the option to set the USB-C port to
>>> prioritise charging or performance. This patch exposes this setting 
>>> to the
>>> userspace via sysfs for all TUXEDO devices supporting it.
>>>
>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>> ---
>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 99 
>>> +++++++++++++++++++--
>>>   1 file changed, 94 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> index 7ab82cf16f388..4d9657a3b8c10 100644
>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> @@ -266,8 +266,8 @@
>>>   #define BATTERY_CHARGE_FULL_OVER_24H    BIT(3)
>>>   #define BATTERY_ERM_STATUS_REACHED    BIT(4)
>>>   -#define EC_ADDR_CHARGE_PRIO        0x07CC
>>> -#define CHARGING_PERFORMANCE        BIT(7)
>>> +#define EC_ADDR_USB_C_POWER_PRIORITY    0x07CC
>>> +#define USB_C_POWER_PRIORITY        BIT(7)
>>>     /* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */
>>>   #define EC_ADDR_LIGHTBAR_BAT_CTRL    0x07E2
>>> @@ -324,6 +324,7 @@
>>>   #define UNIWILL_FEATURE_PRIMARY_FAN        BIT(7)
>>>   #define UNIWILL_FEATURE_SECONDARY_FAN        BIT(8)
>>>   #define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL    BIT(9)
>>> +#define UNIWILL_FEATURE_USB_C_POWER_PRIORITY    BIT(10)
>>>     struct uniwill_data {
>>>       struct device *dev;
>>> @@ -343,6 +344,7 @@ struct uniwill_data {
>>>       struct mutex input_lock;    /* Protects input sequence during 
>>> notify */
>>>       struct input_dev *input_device;
>>>       struct notifier_block nb;
>>> +    unsigned int last_usb_c_power_priority;
>>>   };
>>>     struct uniwill_battery_entry {
>>> @@ -527,6 +529,7 @@ static bool uniwill_writeable_reg(struct device 
>>> *dev, unsigned int reg)
>>>       case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>>       case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>>       case EC_ADDR_CTGP_DB_DB_OFFSET:
>>> +    case EC_ADDR_USB_C_POWER_PRIORITY:
>>>           return true;
>>>       default:
>>>           return false;
>>> @@ -565,6 +568,7 @@ static bool uniwill_readable_reg(struct device 
>>> *dev, unsigned int reg)
>>>       case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>>       case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>>       case EC_ADDR_CTGP_DB_DB_OFFSET:
>>> +    case EC_ADDR_USB_C_POWER_PRIORITY:
>>>           return true;
>>>       default:
>>>           return false;
>>> @@ -587,6 +591,7 @@ static bool uniwill_volatile_reg(struct device 
>>> *dev, unsigned int reg)
>>>       case EC_ADDR_TRIGGER:
>>>       case EC_ADDR_SWITCH_STATUS:
>>>       case EC_ADDR_CHARGE_CTRL:
>>> +    case EC_ADDR_USB_C_POWER_PRIORITY:
>>>           return true;
>>>       default:
>>>           return false;
>>> @@ -883,6 +888,86 @@ static int uniwill_nvidia_ctgp_init(struct 
>>> uniwill_data *data)
>>>       return 0;
>>>   }
>>>   +enum usb_c_power_priority_options {
>>> +    USB_C_POWER_PRIORITY_OPTIONS_CHARGING = 0,
>>> +    USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE,
>>> +};
>>> +
>>> +static const char * const USB_C_POWER_PRIORITY_OPTIONS_TEXT[] = {
>>> +    [USB_C_POWER_PRIORITY_OPTIONS_CHARGING]        = "charging",
>>> +    [USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE]    = "performance",
>>> +};
>>> +
>>> +static const u8 USB_C_POWER_PRIORITY_OPTIONS_VALUE[] = {
>>> +    [USB_C_POWER_PRIORITY_OPTIONS_CHARGING]        = 0,
>>> +    [USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE]    = 
>>> USB_C_POWER_PRIORITY,
>>> +};
>>> +
>>> +static ssize_t usb_c_power_priority_store(struct device *dev,
>>> +                      struct device_attribute *attr,
>>> +                      const char *buf, size_t count)
>>> +{
>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>> +    unsigned int value;
>>> +    int ret;
>>> +
>>> +    ret = sysfs_match_string(USB_C_POWER_PRIORITY_OPTIONS_TEXT, buf);
>>> +    if (ret < 0)
>>> +        return ret;
>>
>> Please put a blank line here.
> ack
>>
>>> +    value = USB_C_POWER_PRIORITY_OPTIONS_VALUE[ret];
>>> +
>>> +    ret = regmap_update_bits(data->regmap, 
>>> EC_ADDR_USB_C_POWER_PRIORITY,
>>> +                 USB_C_POWER_PRIORITY, value);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>
>> I think you need a mutex here, so concurrent writes to the charging 
>> priority
>> sysfs attribute are serialized. This mutex would then also protect 
>> concurrent
>> access to data->last_usb_c_power_priority by the event handler.
> ack
>>
>>> +    data->last_usb_c_power_priority = value;
>>> +
>>> +    return count;
>>> +}
>>> +
>>> +static ssize_t usb_c_power_priority_show(struct device *dev,
>>> +                     struct device_attribute *attr,
>>> +                     char *buf)
>>> +{
>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>> +    unsigned int value;
>>> +    ssize_t count = 0;
>>> +    int ret;
>>> +
>>> +    ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, 
>>> &value);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +    value &= USB_C_POWER_PRIORITY;
>>> +
>>> +    for (int i = 0; i < 
>>> ARRAY_SIZE(USB_C_POWER_PRIORITY_OPTIONS_VALUE); ++i) {
>>> +        if (USB_C_POWER_PRIORITY_OPTIONS_VALUE[i] == value)
>>> +            count += sysfs_emit_at(buf, count, "[%s] ",
>>> + USB_C_POWER_PRIORITY_OPTIONS_TEXT[i]);
>>> +        else
>>> +            count += sysfs_emit_at(buf, count, "%s ",
>>> + USB_C_POWER_PRIORITY_OPTIONS_TEXT[i]);
>>> +    }
>>> +    if (count)
>>> +        buf[count - 1] = '\n';
>>
>> Please just emit 
>> USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE] 
>> directly
>> when the bit is set, and 
>> USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_CHARGING] 
>> otherwise.
>> This for loop provides no real value.
>
> It does give context on which values are available. It it is otherwise 
> not easily deduceable without referring to the documentation.
>
> Also USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE] 
> is BIT(7) which is a kinda random number when expressed as an integer.
>
Sorry, i meant USB_C_POWER_PRIORITY_OPTIONS_TEXT[].

I do not think that using the "option1 [option2]" syntax provides any real benefit here. The users need to read the documentation
anyway in order to even find this attribute, and the set of available options is always the same.

Please drop this.

>>
>>> +
>>> +    return count;
>>> +}
>>> +
>>> +static DEVICE_ATTR_RW(usb_c_power_priority);
>>> +
>>> +static int usb_c_power_priority_restore(struct uniwill_data *data)
>>> +{
>>> +    int ret;
>>> +
>>> +    ret = regmap_update_bits(data->regmap, EC_ADDR_OEM_4, 
>>> USB_C_POWER_PRIORITY,
>>> +                 data->last_usb_c_power_priority);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    return ret;
>>
>> Please check the feature flag here before performing the register 
>> access. You should also
>> omit "ret" and instead return the result directly.
> ack
>>
>> Maybe you also need to add the appropriate suspend/resume functions 
>> for this?
> tuxedo-drivers doesn't have it for this, so it's probably not necessary

Please add the appropriate suspend/resume functions anyway, just in case the user has
connected the charger while the system was suspended.

Thanks,
Armin Wolf

>>
>>> +}
>>> +
>>>   static struct attribute *uniwill_attrs[] = {
>>>       /* Keyboard-related */
>>>       &dev_attr_fn_lock.attr,
>>> @@ -893,6 +978,7 @@ static struct attribute *uniwill_attrs[] = {
>>>       &dev_attr_breathing_in_suspend.attr,
>>>       /* Power-management-related */
>>>       &dev_attr_ctgp_offset.attr,
>>> +    &dev_attr_usb_c_power_priority.attr,
>>>       NULL
>>>   };
>>>   @@ -927,6 +1013,11 @@ static umode_t 
>>> uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
>>>               return attr->mode;
>>>       }
>>>   +    if (attr == &dev_attr_usb_c_power_priority.attr) {
>>> +        if (uniwill_device_supports(data, 
>>> UNIWILL_FEATURE_USB_C_POWER_PRIORITY))
>>> +            return attr->mode;
>>> +    }
>>> +
>>>       return 0;
>>>   }
>>>   @@ -1417,9 +1508,7 @@ static int uniwill_notifier_call(struct 
>>> notifier_block *nb, unsigned long action
>>>             return NOTIFY_OK;
>>>       case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>> -        /* noop for the time being, will change once charging priority
>>> -         * gets implemented.
>>> -         */
>>> +        usb_c_power_priority_restore(data);
>>
>> Please use notifier_from_errno() here.
> ack
>>
>> Thanks,
>> Armin Wolf
>>
>>>             return NOTIFY_OK;
>>>       case UNIWILL_OSD_FN_LOCK:
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/4] platform/x86/uniwill: Implement USB-C power priority setting
  2026-02-27  9:27       ` Armin Wolf
@ 2026-02-27 18:40         ` Werner Sembach
  0 siblings, 0 replies; 12+ messages in thread
From: Werner Sembach @ 2026-02-27 18:40 UTC (permalink / raw)
  To: Armin Wolf, Hans de Goede, Ilpo Järvinen
  Cc: platform-driver-x86, linux-kernel


Am 27.02.26 um 10:27 schrieb Armin Wolf:
> Am 26.02.26 um 16:55 schrieb Werner Sembach:
>
>>
>> Am 26.02.26 um 02:11 schrieb Armin Wolf:
>>> Am 26.02.26 um 01:31 schrieb Werner Sembach:
>>>
>>>> On some devices Uniwill offers the option to set the USB-C port to
>>>> prioritise charging or performance. This patch exposes this setting to the
>>>> userspace via sysfs for all TUXEDO devices supporting it.
>>>>
>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>> ---
>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 99 +++++++++++++++++++--
>>>>   1 file changed, 94 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> index 7ab82cf16f388..4d9657a3b8c10 100644
>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> @@ -266,8 +266,8 @@
>>>>   #define BATTERY_CHARGE_FULL_OVER_24H    BIT(3)
>>>>   #define BATTERY_ERM_STATUS_REACHED    BIT(4)
>>>>   -#define EC_ADDR_CHARGE_PRIO        0x07CC
>>>> -#define CHARGING_PERFORMANCE        BIT(7)
>>>> +#define EC_ADDR_USB_C_POWER_PRIORITY    0x07CC
>>>> +#define USB_C_POWER_PRIORITY        BIT(7)
>>>>     /* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */
>>>>   #define EC_ADDR_LIGHTBAR_BAT_CTRL    0x07E2
>>>> @@ -324,6 +324,7 @@
>>>>   #define UNIWILL_FEATURE_PRIMARY_FAN        BIT(7)
>>>>   #define UNIWILL_FEATURE_SECONDARY_FAN        BIT(8)
>>>>   #define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL    BIT(9)
>>>> +#define UNIWILL_FEATURE_USB_C_POWER_PRIORITY    BIT(10)
>>>>     struct uniwill_data {
>>>>       struct device *dev;
>>>> @@ -343,6 +344,7 @@ struct uniwill_data {
>>>>       struct mutex input_lock;    /* Protects input sequence during notify */
>>>>       struct input_dev *input_device;
>>>>       struct notifier_block nb;
>>>> +    unsigned int last_usb_c_power_priority;
>>>>   };
>>>>     struct uniwill_battery_entry {
>>>> @@ -527,6 +529,7 @@ static bool uniwill_writeable_reg(struct device *dev, 
>>>> unsigned int reg)
>>>>       case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>>>       case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>>>       case EC_ADDR_CTGP_DB_DB_OFFSET:
>>>> +    case EC_ADDR_USB_C_POWER_PRIORITY:
>>>>           return true;
>>>>       default:
>>>>           return false;
>>>> @@ -565,6 +568,7 @@ static bool uniwill_readable_reg(struct device *dev, 
>>>> unsigned int reg)
>>>>       case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>>>       case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>>>       case EC_ADDR_CTGP_DB_DB_OFFSET:
>>>> +    case EC_ADDR_USB_C_POWER_PRIORITY:
>>>>           return true;
>>>>       default:
>>>>           return false;
>>>> @@ -587,6 +591,7 @@ static bool uniwill_volatile_reg(struct device *dev, 
>>>> unsigned int reg)
>>>>       case EC_ADDR_TRIGGER:
>>>>       case EC_ADDR_SWITCH_STATUS:
>>>>       case EC_ADDR_CHARGE_CTRL:
>>>> +    case EC_ADDR_USB_C_POWER_PRIORITY:
>>>>           return true;
>>>>       default:
>>>>           return false;
>>>> @@ -883,6 +888,86 @@ static int uniwill_nvidia_ctgp_init(struct 
>>>> uniwill_data *data)
>>>>       return 0;
>>>>   }
>>>>   +enum usb_c_power_priority_options {
>>>> +    USB_C_POWER_PRIORITY_OPTIONS_CHARGING = 0,
>>>> +    USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE,
>>>> +};
>>>> +
>>>> +static const char * const USB_C_POWER_PRIORITY_OPTIONS_TEXT[] = {
>>>> +    [USB_C_POWER_PRIORITY_OPTIONS_CHARGING]        = "charging",
>>>> +    [USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE]    = "performance",
>>>> +};
>>>> +
>>>> +static const u8 USB_C_POWER_PRIORITY_OPTIONS_VALUE[] = {
>>>> +    [USB_C_POWER_PRIORITY_OPTIONS_CHARGING]        = 0,
>>>> +    [USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE]    = USB_C_POWER_PRIORITY,
>>>> +};
>>>> +
>>>> +static ssize_t usb_c_power_priority_store(struct device *dev,
>>>> +                      struct device_attribute *attr,
>>>> +                      const char *buf, size_t count)
>>>> +{
>>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>>> +    unsigned int value;
>>>> +    int ret;
>>>> +
>>>> +    ret = sysfs_match_string(USB_C_POWER_PRIORITY_OPTIONS_TEXT, buf);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>
>>> Please put a blank line here.
>> ack
>>>
>>>> +    value = USB_C_POWER_PRIORITY_OPTIONS_VALUE[ret];
>>>> +
>>>> +    ret = regmap_update_bits(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY,
>>>> +                 USB_C_POWER_PRIORITY, value);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>
>>> I think you need a mutex here, so concurrent writes to the charging priority
>>> sysfs attribute are serialized. This mutex would then also protect concurrent
>>> access to data->last_usb_c_power_priority by the event handler.
>> ack
>>>
>>>> + data->last_usb_c_power_priority = value;
>>>> +
>>>> +    return count;
>>>> +}
>>>> +
>>>> +static ssize_t usb_c_power_priority_show(struct device *dev,
>>>> +                     struct device_attribute *attr,
>>>> +                     char *buf)
>>>> +{
>>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>>> +    unsigned int value;
>>>> +    ssize_t count = 0;
>>>> +    int ret;
>>>> +
>>>> +    ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +    value &= USB_C_POWER_PRIORITY;
>>>> +
>>>> +    for (int i = 0; i < ARRAY_SIZE(USB_C_POWER_PRIORITY_OPTIONS_VALUE); 
>>>> ++i) {
>>>> +        if (USB_C_POWER_PRIORITY_OPTIONS_VALUE[i] == value)
>>>> +            count += sysfs_emit_at(buf, count, "[%s] ",
>>>> + USB_C_POWER_PRIORITY_OPTIONS_TEXT[i]);
>>>> +        else
>>>> +            count += sysfs_emit_at(buf, count, "%s ",
>>>> + USB_C_POWER_PRIORITY_OPTIONS_TEXT[i]);
>>>> +    }
>>>> +    if (count)
>>>> +        buf[count - 1] = '\n';
>>>
>>> Please just emit 
>>> USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE] 
>>> directly
>>> when the bit is set, and 
>>> USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_CHARGING] 
>>> otherwise.
>>> This for loop provides no real value.
>>
>> It does give context on which values are available. It it is otherwise not 
>> easily deduceable without referring to the documentation.
>>
>> Also USB_C_POWER_PRIORITY_OPTIONS_VALUE[USB_C_POWER_PRIORITY_OPTIONS_PERFORMANCE] 
>> is BIT(7) which is a kinda random number when expressed as an integer.
>>
> Sorry, i meant USB_C_POWER_PRIORITY_OPTIONS_TEXT[].
>
> I do not think that using the "option1 [option2]" syntax provides any real 
> benefit here. The users need to read the documentation
> anyway in order to even find this attribute, and the set of available options 
> is always the same.
>
> Please drop this.
ok
>
>>>
>>>> +
>>>> +    return count;
>>>> +}
>>>> +
>>>> +static DEVICE_ATTR_RW(usb_c_power_priority);
>>>> +
>>>> +static int usb_c_power_priority_restore(struct uniwill_data *data)
>>>> +{
>>>> +    int ret;
>>>> +
>>>> +    ret = regmap_update_bits(data->regmap, EC_ADDR_OEM_4, 
>>>> USB_C_POWER_PRIORITY,
>>>> +                 data->last_usb_c_power_priority);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    return ret;
>>>
>>> Please check the feature flag here before performing the register access. 
>>> You should also
>>> omit "ret" and instead return the result directly.
>> ack
>>>
>>> Maybe you also need to add the appropriate suspend/resume functions for this?
>> tuxedo-drivers doesn't have it for this, so it's probably not necessary
>
> Please add the appropriate suspend/resume functions anyway, just in case the 
> user has
> connected the charger while the system was suspended.
ok, suspend is actually not necessary because last value is already saved on write
>
> Thanks,
> Armin Wolf
>
>>>
>>>> +}
>>>> +
>>>>   static struct attribute *uniwill_attrs[] = {
>>>>       /* Keyboard-related */
>>>>       &dev_attr_fn_lock.attr,
>>>> @@ -893,6 +978,7 @@ static struct attribute *uniwill_attrs[] = {
>>>>       &dev_attr_breathing_in_suspend.attr,
>>>>       /* Power-management-related */
>>>>       &dev_attr_ctgp_offset.attr,
>>>> +    &dev_attr_usb_c_power_priority.attr,
>>>>       NULL
>>>>   };
>>>>   @@ -927,6 +1013,11 @@ static umode_t uniwill_attr_is_visible(struct 
>>>> kobject *kobj, struct attribute *a
>>>>               return attr->mode;
>>>>       }
>>>>   +    if (attr == &dev_attr_usb_c_power_priority.attr) {
>>>> +        if (uniwill_device_supports(data, 
>>>> UNIWILL_FEATURE_USB_C_POWER_PRIORITY))
>>>> +            return attr->mode;
>>>> +    }
>>>> +
>>>>       return 0;
>>>>   }
>>>>   @@ -1417,9 +1508,7 @@ static int uniwill_notifier_call(struct 
>>>> notifier_block *nb, unsigned long action
>>>>             return NOTIFY_OK;
>>>>       case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>> -        /* noop for the time being, will change once charging priority
>>>> -         * gets implemented.
>>>> -         */
>>>> +        usb_c_power_priority_restore(data);
>>>
>>> Please use notifier_from_errno() here.
>> ack
>>>
>>> Thanks,
>>> Armin Wolf
>>>
>>>>             return NOTIFY_OK;
>>>>       case UNIWILL_OSD_FN_LOCK:
>>

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-02-27 18:40 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-26  0:31 [PATCH 1/4] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines Werner Sembach
2026-02-26  0:31 ` [PATCH 2/4] platform/x86/uniwill: Implement USB-C power priority setting Werner Sembach
2026-02-26  1:11   ` Armin Wolf
2026-02-26 15:55     ` Werner Sembach
2026-02-27  9:27       ` Armin Wolf
2026-02-27 18:40         ` Werner Sembach
2026-02-26  0:31 ` [PATCH 3/4] platform/x86/uniwill: Apply features across all TUXEDO devices Werner Sembach
2026-02-26  1:15   ` Armin Wolf
2026-02-26 20:14     ` Werner Sembach
2026-02-26  0:31 ` [PATCH 4/4] Documentation: laptops: Update documentation for uniwill laptops Werner Sembach
2026-02-26  1:17   ` Armin Wolf
2026-02-26  0:58 ` [PATCH 1/4] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines Armin Wolf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox