* [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support
@ 2026-11-10 16:50 Armin Wolf
2026-11-10 16:50 ` [PATCH v2 1/9] power: supply: core: Add power_supply_has_property_direct() Armin Wolf
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Armin Wolf @ 2026-11-10 16:50 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, bifangknt, nicokessler, sre,
linux-pm, wse
According to the work item for upstreaming the out-of-tree
tuxedo-drivers package, the mainline uniwill-laptop driver still does
not allow userspace to read the cycle count and raw capacity of the
battery, preventing Tuxedo Computers from switching over to the
mainline driver (among other things).
This patch series aims to add the missing battery-related bits. The
first two patches extend the power supply subsystem, while the third
patch uses the new API to expose the battery cycle count on devices
where this not already being done by the ACPI firmware itself. The
fourth patch also exposes the raw battery capacity using a custom
sysfs attribute below the battery power supply device. The fifth
patch only does some generic sysfs-related cleanup, while the last
three patches add support for new devices based on user reports.
All patches have been tested on a TUXEDO InfinityBook Pro 14 Gen10 AMD
and appear to work without issues.
Link: https://gitlab.com/tuxedocomputers/development/packages/tuxedo-drivers/-/work_items/253
Changes since v2:
- fix error handling inside patch 5
Armin Wolf (9):
power: supply: core: Add power_supply_has_property_direct()
power: supply: Enable struct power_supply_ext to be construct
dynamically
platform/x86: uniwill-laptop: Report battery cycle count
platform/x86: uniwill-laptop: Expose battery health and cycle count on
all devices
platform/x86: uniwill-laptop: Expose raw battery capacity to userspace
platform/x86: uniwill-laptop: Mark sysfs attributes as const
platform/x86: uniwill-laptop: Add support for MECHREVO Yilong15Pro
platform/x86: uniwill-laptop: Add MECHREVO JIAOLONG Series-X6xR55xK
platform/x86: uniwill-laptop: Add support for XMG EVO 14 (E25)
.../ABI/testing/sysfs-driver-uniwill-laptop | 11 +
drivers/platform/x86/uniwill/uniwill-acpi.c | 269 ++++++++++++------
drivers/power/supply/power_supply_core.c | 26 +-
include/linux/power_supply.h | 3 +-
4 files changed, 220 insertions(+), 89 deletions(-)
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/9] power: supply: core: Add power_supply_has_property_direct()
2026-11-10 16:50 [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
@ 2026-11-10 16:50 ` Armin Wolf
2026-11-10 16:50 ` [PATCH v2 2/9] power: supply: Enable struct power_supply_ext to be construct dynamically Armin Wolf
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Armin Wolf @ 2026-11-10 16:50 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, bifangknt, nicokessler, sre,
linux-pm, wse
Providers of power supply extensions might want to check if a given
power supply supports a given property in order to select a suitable
extension to load.
Add power_supply_has_property_direct() to enable such use cases.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/power/supply/power_supply_core.c | 26 ++++++++++++++++++++----
include/linux/power_supply.h | 1 +
2 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index 1cc203f2780b..75b53aec5db4 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -1367,17 +1367,35 @@ bool power_supply_ext_has_property(const struct power_supply_ext *psy_ext,
return false;
}
-bool power_supply_has_property(struct power_supply *psy,
- enum power_supply_property psp)
+/**
+ * power_supply_has_property_direct - Check if a power supply property exists without checking
+ * for extensions
+ * @psy: The power supply
+ * @psp: The power supply property to check
+ *
+ * Check if a given power supply support a given power supply property without taking into account
+ * any power supply extesions registered on said power supply. This is mostly useful for determining
+ * if a power supply extension should be registered for the power supply or not.
+ */
+bool power_supply_has_property_direct(struct power_supply *psy, enum power_supply_property psp)
{
- struct power_supply_ext_registration *reg;
-
if (psy_desc_has_property(psy->desc, psp))
return true;
if (power_supply_battery_info_has_prop(psy->battery_info, psp))
return true;
+ return false;
+}
+EXPORT_SYMBOL_GPL(power_supply_has_property_direct);
+
+bool power_supply_has_property(struct power_supply *psy, enum power_supply_property psp)
+{
+ struct power_supply_ext_registration *reg;
+
+ if (power_supply_has_property_direct(psy, psp))
+ return true;
+
power_supply_for_each_extension(reg, psy) {
if (power_supply_ext_has_property(reg->ext, psp))
return true;
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index cce61137aef4..73bcb127d0fc 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -934,6 +934,7 @@ extern int power_supply_is_system_supplied(void);
static inline int power_supply_is_system_supplied(void) { return -ENOSYS; }
#endif
+bool power_supply_has_property_direct(struct power_supply *psy, enum power_supply_property psp);
extern int power_supply_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val);
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 2/9] power: supply: Enable struct power_supply_ext to be construct dynamically
2026-11-10 16:50 [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
2026-11-10 16:50 ` [PATCH v2 1/9] power: supply: core: Add power_supply_has_property_direct() Armin Wolf
@ 2026-11-10 16:50 ` Armin Wolf
2026-11-10 16:50 ` [PATCH v2 3/9] platform/x86: uniwill-laptop: Report battery cycle count Armin Wolf
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Armin Wolf @ 2026-11-10 16:50 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, bifangknt, nicokessler, sre,
linux-pm, wse
Providers of power supply extensions currently cannot construct them
dynamically because the pointer to the name string is declared as
being const, even when the remaining members of
struct power_supply_ext are not declared as being const.
Remove this pointless restriction to allow providers to dynamically
construct power supply extensions.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
include/linux/power_supply.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 73bcb127d0fc..a0cabc139298 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -318,7 +318,7 @@ struct power_supply_desc {
};
struct power_supply_ext {
- const char *const name;
+ const char *name;
u8 charge_behaviours;
u32 charge_types;
const enum power_supply_property *properties;
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 3/9] platform/x86: uniwill-laptop: Report battery cycle count
2026-11-10 16:50 [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
2026-11-10 16:50 ` [PATCH v2 1/9] power: supply: core: Add power_supply_has_property_direct() Armin Wolf
2026-11-10 16:50 ` [PATCH v2 2/9] power: supply: Enable struct power_supply_ext to be construct dynamically Armin Wolf
@ 2026-11-10 16:50 ` Armin Wolf
2026-11-10 16:50 ` [PATCH v2 4/9] platform/x86: uniwill-laptop: Expose battery health and cycle count on all devices Armin Wolf
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Armin Wolf @ 2026-11-10 16:50 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, bifangknt, nicokessler, sre,
linux-pm, wse
It turns out that nearly all Uniwill-based devices do not support
the _BIX ACPI control method for ACPI battery devices, instead only
providing the legacy _BIF ACPI control method. This prevents them
from reporting the cycle count of the battery, even when the EC
reports this value.
Fix this by supplying the battery cycle count using the power supply
extension on devices where the ACPI battery does not.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 94 ++++++++++++---------
1 file changed, 55 insertions(+), 39 deletions(-)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 060324ed3c4d..1958a1bfc880 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -392,6 +392,9 @@ struct uniwill_data {
};
unsigned int last_charge_ctrl;
};
+ enum power_supply_property extension_props[3];
+ struct power_supply_ext standard_extension;
+ struct power_supply_ext cycle_count_extension;
bool last_fn_lock_state;
bool last_super_key_enable_state;
bool last_touchpad_toggle_enable_state;
@@ -639,6 +642,8 @@ static bool uniwill_readable_reg(struct device *dev, unsigned int reg)
case EC_ADDR_SECOND_FAN_RPM_1:
case EC_ADDR_SECOND_FAN_RPM_2:
case EC_ADDR_BAT_ALERT:
+ case EC_ADDR_BAT_CYCLE_COUNT_1:
+ case EC_ADDR_BAT_CYCLE_COUNT_2:
case EC_ADDR_OEM_9:
case EC_ADDR_PROJECT_ID:
case EC_ADDR_AP_OEM:
@@ -686,6 +691,8 @@ static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
case EC_ADDR_SECOND_FAN_RPM_1:
case EC_ADDR_SECOND_FAN_RPM_2:
case EC_ADDR_BAT_ALERT:
+ case EC_ADDR_BAT_CYCLE_COUNT_1:
+ case EC_ADDR_BAT_CYCLE_COUNT_2:
case EC_ADDR_BIOS_OEM:
case EC_ADDR_PWM_1:
case EC_ADDR_PWM_2:
@@ -1966,6 +1973,7 @@ static int uniwill_get_property(struct power_supply *psy, const struct power_sup
struct uniwill_data *data = drvdata;
union power_supply_propval prop;
unsigned int regval;
+ __le16 cycle_count;
int ret;
switch (psp) {
@@ -2010,6 +2018,14 @@ static int uniwill_get_property(struct power_supply *psy, const struct power_sup
val->intval = POWER_SUPPLY_HEALTH_GOOD;
return 0;
+ case POWER_SUPPLY_PROP_CYCLE_COUNT:
+ ret = regmap_bulk_read(data->regmap, EC_ADDR_BAT_CYCLE_COUNT_1, &cycle_count,
+ sizeof(cycle_count));
+ if (ret < 0)
+ return ret;
+
+ val->intval = le16_to_cpu(cycle_count);
+ return 0;
case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
ret = regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, ®val);
if (ret < 0)
@@ -2093,54 +2109,23 @@ static int uniwill_property_is_writeable(struct power_supply *psy,
}
}
-static const enum power_supply_property uniwill_charge_limit_properties[] = {
- POWER_SUPPLY_PROP_HEALTH,
- POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
-};
-
-static const struct power_supply_ext uniwill_charge_limit_extension = {
- .name = DRIVER_NAME,
- .properties = uniwill_charge_limit_properties,
- .num_properties = ARRAY_SIZE(uniwill_charge_limit_properties),
- .get_property = uniwill_get_property,
- .set_property = uniwill_set_property,
- .property_is_writeable = uniwill_property_is_writeable,
-};
-
-static const enum power_supply_property uniwill_charge_modes_properties[] = {
- POWER_SUPPLY_PROP_CHARGE_TYPES,
- POWER_SUPPLY_PROP_HEALTH,
-};
-
-static const struct power_supply_ext uniwill_charge_modes_extension = {
- .name = DRIVER_NAME,
- .charge_types = BIT(POWER_SUPPLY_CHARGE_TYPE_TRICKLE) |
- BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
- BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE),
- .properties = uniwill_charge_modes_properties,
- .num_properties = ARRAY_SIZE(uniwill_charge_modes_properties),
- .get_property = uniwill_get_property,
- .set_property = uniwill_set_property,
- .property_is_writeable = uniwill_property_is_writeable,
-};
-
static int uniwill_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
{
struct uniwill_data *data = container_of(hook, struct uniwill_data, hook);
struct uniwill_battery_entry *entry;
+ const struct power_supply_ext *ext;
int ret;
entry = kzalloc_obj(*entry);
if (!entry)
return -ENOMEM;
- if (uniwill_device_supports(data, UNIWILL_FEATURE_BATTERY_CHARGE_LIMIT))
- ret = power_supply_register_extension(battery, &uniwill_charge_limit_extension,
- data->dev, data);
+ if (power_supply_has_property_direct(battery, POWER_SUPPLY_PROP_CYCLE_COUNT))
+ ext = &data->standard_extension;
else
- ret = power_supply_register_extension(battery, &uniwill_charge_modes_extension,
- data->dev, data);
+ ext = &data->cycle_count_extension;
+ ret = power_supply_register_extension(battery, ext, data->dev, data);
if (ret < 0) {
kfree(entry);
return ret;
@@ -2158,6 +2143,7 @@ static int uniwill_remove_battery(struct power_supply *battery, struct acpi_batt
{
struct uniwill_data *data = container_of(hook, struct uniwill_data, hook);
struct uniwill_battery_entry *entry, *tmp;
+ const struct power_supply_ext *ext;
scoped_guard(mutex, &data->battery_lock) {
list_for_each_entry_safe(entry, tmp, &data->batteries, head) {
@@ -2169,10 +2155,12 @@ static int uniwill_remove_battery(struct power_supply *battery, struct acpi_batt
}
}
- if (uniwill_device_supports(data, UNIWILL_FEATURE_BATTERY_CHARGE_LIMIT))
- power_supply_unregister_extension(battery, &uniwill_charge_limit_extension);
+ if (power_supply_has_property_direct(battery, POWER_SUPPLY_PROP_CYCLE_COUNT))
+ ext = &data->standard_extension;
else
- power_supply_unregister_extension(battery, &uniwill_charge_modes_extension);
+ ext = &data->cycle_count_extension;
+
+ power_supply_unregister_extension(battery, ext);
return 0;
}
@@ -2180,6 +2168,9 @@ static int uniwill_remove_battery(struct power_supply *battery, struct acpi_batt
static int uniwill_battery_init(struct uniwill_data *data)
{
unsigned int value, threshold, sanitized;
+ u32 charge_types = BIT(POWER_SUPPLY_CHARGE_TYPE_TRICKLE) |
+ BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
+ BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE);
int ret;
if (uniwill_device_supports(data, UNIWILL_FEATURE_BATTERY_CHARGE_LIMIT)) {
@@ -2203,6 +2194,8 @@ static int uniwill_battery_init(struct uniwill_data *data)
if (ret < 0)
return ret;
}
+
+ data->extension_props[0] = POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD;
} else if (uniwill_device_supports(data, UNIWILL_FEATURE_BATTERY_CHARGE_MODES)) {
ret = devm_mutex_init(data->dev, &data->charge_type_lock);
if (ret < 0)
@@ -2211,10 +2204,33 @@ static int uniwill_battery_init(struct uniwill_data *data)
ret = uniwill_read_charge_type(data, &data->last_charge_type);
if (ret < 0)
return ret;
+
+ data->extension_props[0] = POWER_SUPPLY_PROP_CHARGE_TYPES;
+ data->standard_extension.charge_types = charge_types;
+ data->cycle_count_extension.charge_types = charge_types;
} else {
return 0;
}
+ data->extension_props[1] = POWER_SUPPLY_PROP_HEALTH;
+ /* Needs to come last */
+ data->extension_props[2] = POWER_SUPPLY_PROP_CYCLE_COUNT;
+
+ data->standard_extension.name = DRIVER_NAME;
+ data->standard_extension.properties = data->extension_props;
+ /* POWER_SUPPLY_PROP_CYCLE_COUNT is usually already provided by the ACPI battery */
+ data->standard_extension.num_properties = ARRAY_SIZE(data->extension_props) - 1;
+ data->standard_extension.get_property = uniwill_get_property;
+ data->standard_extension.set_property = uniwill_set_property;
+ data->standard_extension.property_is_writeable = uniwill_property_is_writeable;
+
+ data->cycle_count_extension.name = DRIVER_NAME;
+ data->cycle_count_extension.properties = data->extension_props;
+ data->cycle_count_extension.num_properties = ARRAY_SIZE(data->extension_props);
+ data->cycle_count_extension.get_property = uniwill_get_property;
+ data->cycle_count_extension.set_property = uniwill_set_property;
+ data->cycle_count_extension.property_is_writeable = uniwill_property_is_writeable;
+
ret = devm_mutex_init(data->dev, &data->battery_lock);
if (ret < 0)
return ret;
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 4/9] platform/x86: uniwill-laptop: Expose battery health and cycle count on all devices
2026-11-10 16:50 [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (2 preceding siblings ...)
2026-11-10 16:50 ` [PATCH v2 3/9] platform/x86: uniwill-laptop: Report battery cycle count Armin Wolf
@ 2026-11-10 16:50 ` Armin Wolf
2026-11-10 16:50 ` [PATCH v2 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace Armin Wolf
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Armin Wolf @ 2026-11-10 16:50 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, bifangknt, nicokessler, sre,
linux-pm, wse
We can assume that all passive battery properties (health and cycle
count) are available on all devices if the underlying EC interface
is supported. Rework the battery extension initialization code to
always register a power supply extension with at least those two
properties.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 1958a1bfc880..66770f939c83 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -2171,6 +2171,7 @@ static int uniwill_battery_init(struct uniwill_data *data)
u32 charge_types = BIT(POWER_SUPPLY_CHARGE_TYPE_TRICKLE) |
BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE);
+ int i = 0;
int ret;
if (uniwill_device_supports(data, UNIWILL_FEATURE_BATTERY_CHARGE_LIMIT)) {
@@ -2195,7 +2196,7 @@ static int uniwill_battery_init(struct uniwill_data *data)
return ret;
}
- data->extension_props[0] = POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD;
+ data->extension_props[i++] = POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD;
} else if (uniwill_device_supports(data, UNIWILL_FEATURE_BATTERY_CHARGE_MODES)) {
ret = devm_mutex_init(data->dev, &data->charge_type_lock);
if (ret < 0)
@@ -2205,28 +2206,26 @@ static int uniwill_battery_init(struct uniwill_data *data)
if (ret < 0)
return ret;
- data->extension_props[0] = POWER_SUPPLY_PROP_CHARGE_TYPES;
+ data->extension_props[i++] = POWER_SUPPLY_PROP_CHARGE_TYPES;
data->standard_extension.charge_types = charge_types;
data->cycle_count_extension.charge_types = charge_types;
- } else {
- return 0;
}
- data->extension_props[1] = POWER_SUPPLY_PROP_HEALTH;
+ data->extension_props[i++] = POWER_SUPPLY_PROP_HEALTH;
/* Needs to come last */
- data->extension_props[2] = POWER_SUPPLY_PROP_CYCLE_COUNT;
+ data->extension_props[i++] = POWER_SUPPLY_PROP_CYCLE_COUNT;
data->standard_extension.name = DRIVER_NAME;
data->standard_extension.properties = data->extension_props;
/* POWER_SUPPLY_PROP_CYCLE_COUNT is usually already provided by the ACPI battery */
- data->standard_extension.num_properties = ARRAY_SIZE(data->extension_props) - 1;
+ data->standard_extension.num_properties = i - 1;
data->standard_extension.get_property = uniwill_get_property;
data->standard_extension.set_property = uniwill_set_property;
data->standard_extension.property_is_writeable = uniwill_property_is_writeable;
data->cycle_count_extension.name = DRIVER_NAME;
data->cycle_count_extension.properties = data->extension_props;
- data->cycle_count_extension.num_properties = ARRAY_SIZE(data->extension_props);
+ data->cycle_count_extension.num_properties = i;
data->cycle_count_extension.get_property = uniwill_get_property;
data->cycle_count_extension.set_property = uniwill_set_property;
data->cycle_count_extension.property_is_writeable = uniwill_property_is_writeable;
@@ -2251,11 +2250,6 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
switch (action) {
case UNIWILL_OSD_BATTERY_ALERT:
- if (!uniwill_device_supports_any(data,
- UNIWILL_FEATURE_BATTERY_CHARGE_LIMIT |
- UNIWILL_FEATURE_BATTERY_CHARGE_MODES))
- return NOTIFY_DONE;
-
mutex_lock(&data->battery_lock);
list_for_each_entry(entry, &data->batteries, head) {
power_supply_changed(entry->battery);
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace
2026-11-10 16:50 [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (3 preceding siblings ...)
2026-11-10 16:50 ` [PATCH v2 4/9] platform/x86: uniwill-laptop: Expose battery health and cycle count on all devices Armin Wolf
@ 2026-11-10 16:50 ` Armin Wolf
2026-11-10 16:50 ` [PATCH v2 6/9] platform/x86: uniwill-laptop: Mark sysfs attributes as const Armin Wolf
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Armin Wolf @ 2026-11-10 16:50 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, bifangknt, nicokessler, sre,
linux-pm, wse
It turns out that Uniwill will not report the true battery full charge
capacity for the first 64 charge cycles. While this is likely being
done for correctly calibrating the battery, it still prevents custom
diagnostic software from accurately detecting the battery wear.
Fix this by exposing the raw battery full charge capacity to userspace
using a custom sysfs attribute.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
.../ABI/testing/sysfs-driver-uniwill-laptop | 11 +++++
drivers/platform/x86/uniwill/uniwill-acpi.c | 48 ++++++++++++++++---
2 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
index f3060aaf8a76..5f7eccb2d205 100644
--- a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
+++ b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
@@ -92,3 +92,14 @@ Description:
boot at the same time is not supported.
Reading this file returns the current status of the USB powershare functionality.
+
+What: /sys/class/power_supply/<battery_name>/charge_full_raw
+Date: December 2026
+KernelVersion: 7.5
+Contact: Armin Wolf <W_Armin@gmx.de>
+Description:
+ Allows userspace applications to read the raw full charge capacity of the
+ battery. This value might differ from the full chage capacity reported by the
+ battery itself, usually caused by postprocessing done inside the ACPI firmware.
+
+ Reading this file returns the raw full charge capacity in µAh of the battery.
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 66770f939c83..ef3e77446112 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -395,6 +395,7 @@ struct uniwill_data {
enum power_supply_property extension_props[3];
struct power_supply_ext standard_extension;
struct power_supply_ext cycle_count_extension;
+ struct device_attribute charge_full_raw_attr;
bool last_fn_lock_state;
bool last_super_key_enable_state;
bool last_touchpad_toggle_enable_state;
@@ -635,6 +636,8 @@ static bool uniwill_writeable_reg(struct device *dev, unsigned int reg)
static bool uniwill_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case EC_ADDR_BAT_FULL_CAPACITY_1:
+ case EC_ADDR_BAT_FULL_CAPACITY_2:
case EC_ADDR_CPU_TEMP:
case EC_ADDR_GPU_TEMP:
case EC_ADDR_MAIN_FAN_RPM_1:
@@ -684,6 +687,8 @@ static bool uniwill_readable_reg(struct device *dev, unsigned int reg)
static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case EC_ADDR_BAT_FULL_CAPACITY_1:
+ case EC_ADDR_BAT_FULL_CAPACITY_2:
case EC_ADDR_CPU_TEMP:
case EC_ADDR_GPU_TEMP:
case EC_ADDR_MAIN_FAN_RPM_1:
@@ -1932,6 +1937,21 @@ static int uniwill_kbd_led_init(struct uniwill_data *data)
return uniwill_rgb_kbd_led_init(data);
}
+static ssize_t charge_full_raw_show(struct device *dev, const struct device_attribute *attr,
+ char *buf)
+{
+ const struct uniwill_data *data = container_of_const(attr, struct uniwill_data,
+ charge_full_raw_attr);
+ __le16 value;
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, EC_ADDR_BAT_FULL_CAPACITY_1, &value, sizeof(value));
+ if (ret < 0)
+ return ret;
+
+ return sysfs_emit(buf, "%u\n", le16_to_cpu(value) * 1000);
+}
+
static unsigned int uniwill_sanitize_battery_threshold(unsigned int value)
{
/* 0 means "charging threshold not active" */
@@ -2120,23 +2140,33 @@ static int uniwill_add_battery(struct power_supply *battery, struct acpi_battery
if (!entry)
return -ENOMEM;
+ ret = device_create_file(&battery->dev, &data->charge_full_raw_attr);
+ if (ret < 0)
+ goto err_free;
+
if (power_supply_has_property_direct(battery, POWER_SUPPLY_PROP_CYCLE_COUNT))
ext = &data->standard_extension;
else
ext = &data->cycle_count_extension;
ret = power_supply_register_extension(battery, ext, data->dev, data);
- if (ret < 0) {
- kfree(entry);
- return ret;
- }
-
- guard(mutex)(&data->battery_lock);
+ if (ret < 0)
+ goto err_remove;
entry->battery = battery;
+ mutex_lock(&data->battery_lock);
list_add(&entry->head, &data->batteries);
+ mutex_unlock(&data->battery_lock);
return 0;
+
+err_remove:
+ device_remove_file(&battery->dev, &data->charge_full_raw_attr);
+
+err_free:
+ kfree(entry);
+
+ return ret;
}
static int uniwill_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
@@ -2155,6 +2185,7 @@ static int uniwill_remove_battery(struct power_supply *battery, struct acpi_batt
}
}
+ device_remove_file(&battery->dev, &data->charge_full_raw_attr);
if (power_supply_has_property_direct(battery, POWER_SUPPLY_PROP_CYCLE_COUNT))
ext = &data->standard_extension;
else
@@ -2239,6 +2270,11 @@ static int uniwill_battery_init(struct uniwill_data *data)
data->hook.add_battery = uniwill_add_battery;
data->hook.remove_battery = uniwill_remove_battery;
+ sysfs_attr_init(&data->charge_full_raw_attr.attr);
+ data->charge_full_raw_attr.attr.name = "charge_full_raw";
+ data->charge_full_raw_attr.attr.mode = 0444;
+ data->charge_full_raw_attr.show_const = charge_full_raw_show;
+
return devm_battery_hook_register(data->dev, &data->hook);
}
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 6/9] platform/x86: uniwill-laptop: Mark sysfs attributes as const
2026-11-10 16:50 [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (4 preceding siblings ...)
2026-11-10 16:50 ` [PATCH v2 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace Armin Wolf
@ 2026-11-10 16:50 ` Armin Wolf
2026-11-10 16:50 ` [PATCH v2 7/9] platform/x86: uniwill-laptop: Add support for MECHREVO Yilong15Pro Armin Wolf
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Armin Wolf @ 2026-11-10 16:50 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, bifangknt, nicokessler, sre,
linux-pm, wse
Mark all sysfs attributes as const so that they can be placed in
read only memory for increased security.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 63 ++++++++++-----------
1 file changed, 31 insertions(+), 32 deletions(-)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index ef3e77446112..fbb704cf6e66 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -740,8 +740,8 @@ static int uniwill_write_fn_lock(struct uniwill_data *data, bool status)
return regmap_update_bits(data->regmap, EC_ADDR_BIOS_OEM, FN_LOCK_STATUS, value);
}
-static ssize_t fn_lock_store(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
+static ssize_t fn_lock_store(struct device *dev, const struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
bool enable;
@@ -772,7 +772,7 @@ static int uniwill_read_fn_lock(struct uniwill_data *data, bool *status)
return 0;
}
-static ssize_t fn_lock_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t fn_lock_show(struct device *dev, const struct device_attribute *attr, char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
bool status;
@@ -785,7 +785,7 @@ static ssize_t fn_lock_show(struct device *dev, struct device_attribute *attr, c
return sysfs_emit(buf, "%d\n", status);
}
-static DEVICE_ATTR_RW(fn_lock);
+static const DEVICE_ATTR_RW(fn_lock);
static int uniwill_write_super_key_enable(struct uniwill_data *data, bool status)
{
@@ -809,7 +809,7 @@ static int uniwill_write_super_key_enable(struct uniwill_data *data, bool status
TRIGGER_SUPER_KEY_LOCK);
}
-static ssize_t super_key_enable_store(struct device *dev, struct device_attribute *attr,
+static ssize_t super_key_enable_store(struct device *dev, const struct device_attribute *attr,
const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -841,7 +841,8 @@ static int uniwill_read_super_key_enable(struct uniwill_data *data, bool *status
return 0;
}
-static ssize_t super_key_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t super_key_enable_show(struct device *dev, const struct device_attribute *attr,
+ char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
bool status;
@@ -854,7 +855,7 @@ static ssize_t super_key_enable_show(struct device *dev, struct device_attribute
return sysfs_emit(buf, "%d\n", status);
}
-static DEVICE_ATTR_RW(super_key_enable);
+static const DEVICE_ATTR_RW(super_key_enable);
static int uniwill_write_touchpad_toggle_enable(struct uniwill_data *data, bool status)
{
@@ -868,7 +869,7 @@ static int uniwill_write_touchpad_toggle_enable(struct uniwill_data *data, bool
return regmap_update_bits(data->regmap, EC_ADDR_OEM_4, TOUCHPAD_TOGGLE_OFF, value);
}
-static ssize_t touchpad_toggle_enable_store(struct device *dev, struct device_attribute *attr,
+static ssize_t touchpad_toggle_enable_store(struct device *dev, const struct device_attribute *attr,
const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -900,7 +901,7 @@ static int uniwill_read_touchpad_toggle_enable(struct uniwill_data *data, bool *
return 0;
}
-static ssize_t touchpad_toggle_enable_show(struct device *dev, struct device_attribute *attr,
+static ssize_t touchpad_toggle_enable_show(struct device *dev, const struct device_attribute *attr,
char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -914,9 +915,9 @@ static ssize_t touchpad_toggle_enable_show(struct device *dev, struct device_att
return sysfs_emit(buf, "%d\n", status);
}
-static DEVICE_ATTR_RW(touchpad_toggle_enable);
+static const DEVICE_ATTR_RW(touchpad_toggle_enable);
-static ssize_t breathing_in_suspend_store(struct device *dev, struct device_attribute *attr,
+static ssize_t breathing_in_suspend_store(struct device *dev, const struct device_attribute *attr,
const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -942,7 +943,7 @@ static ssize_t breathing_in_suspend_store(struct device *dev, struct device_attr
return count;
}
-static ssize_t breathing_in_suspend_show(struct device *dev, struct device_attribute *attr,
+static ssize_t breathing_in_suspend_show(struct device *dev, const struct device_attribute *attr,
char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -960,9 +961,9 @@ static ssize_t breathing_in_suspend_show(struct device *dev, struct device_attri
return sysfs_emit(buf, "%d\n", !(value & LIGHTBAR_S3_OFF));
}
-static DEVICE_ATTR_RW(breathing_in_suspend);
+static const DEVICE_ATTR_RW(breathing_in_suspend);
-static ssize_t ctgp_offset_store(struct device *dev, struct device_attribute *attr,
+static ssize_t ctgp_offset_store(struct device *dev, const struct device_attribute *attr,
const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -983,7 +984,7 @@ static ssize_t ctgp_offset_store(struct device *dev, struct device_attribute *at
return count;
}
-static ssize_t ctgp_offset_show(struct device *dev, struct device_attribute *attr,
+static ssize_t ctgp_offset_show(struct device *dev, const struct device_attribute *attr,
char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -997,7 +998,7 @@ static ssize_t ctgp_offset_show(struct device *dev, struct device_attribute *att
return sysfs_emit(buf, "%u\n", value);
}
-static DEVICE_ATTR_RW(ctgp_offset);
+static const DEVICE_ATTR_RW(ctgp_offset);
static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
{
@@ -1036,8 +1037,7 @@ static const u8 usb_c_power_priority_value[] = {
[USB_C_POWER_PRIORITY_PERFORMANCE] = USB_C_POWER_PRIORITY,
};
-static ssize_t usb_c_power_priority_store(struct device *dev,
- struct device_attribute *attr,
+static ssize_t usb_c_power_priority_store(struct device *dev, const struct device_attribute *attr,
const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -1064,8 +1064,7 @@ static ssize_t usb_c_power_priority_store(struct device *dev,
return count;
}
-static ssize_t usb_c_power_priority_show(struct device *dev,
- struct device_attribute *attr,
+static ssize_t usb_c_power_priority_show(struct device *dev, const struct device_attribute *attr,
char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -1085,7 +1084,7 @@ static ssize_t usb_c_power_priority_show(struct device *dev,
return sysfs_emit(buf, "%s\n", usb_c_power_priority_text[USB_C_POWER_PRIORITY_CHARGING]);
}
-static DEVICE_ATTR_RW(usb_c_power_priority);
+static const DEVICE_ATTR_RW(usb_c_power_priority);
static int usb_c_power_priority_restore(struct uniwill_data *data)
{
@@ -1125,7 +1124,7 @@ static int usb_c_power_priority_init(struct uniwill_data *data)
return 0;
}
-static ssize_t ac_auto_boot_store(struct device *dev, struct device_attribute *attr,
+static ssize_t ac_auto_boot_store(struct device *dev, const struct device_attribute *attr,
const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -1149,7 +1148,7 @@ static ssize_t ac_auto_boot_store(struct device *dev, struct device_attribute *a
return count;
}
-static ssize_t ac_auto_boot_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t ac_auto_boot_show(struct device *dev, const struct device_attribute *attr, char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int regval;
@@ -1162,7 +1161,7 @@ static ssize_t ac_auto_boot_show(struct device *dev, struct device_attribute *at
return sysfs_emit(buf, "%d\n", !!(regval & AC_AUTO_BOOT_ENABLE));
}
-static DEVICE_ATTR_RW(ac_auto_boot);
+static const DEVICE_ATTR_RW(ac_auto_boot);
static int uniwill_write_usb_powershare_high(struct uniwill_data *data, bool status)
{
@@ -1180,7 +1179,7 @@ static int uniwill_write_usb_powershare_high(struct uniwill_data *data, bool sta
return regmap_update_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_USB_CHARGING, value);
}
-static ssize_t usb_powershare_high_store(struct device *dev, struct device_attribute *attr,
+static ssize_t usb_powershare_high_store(struct device *dev, const struct device_attribute *attr,
const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -1212,7 +1211,7 @@ static int uniwill_read_usb_powershare_high(struct uniwill_data *data, bool *sta
return 0;
}
-static ssize_t usb_powershare_high_show(struct device *dev, struct device_attribute *attr,
+static ssize_t usb_powershare_high_show(struct device *dev, const struct device_attribute *attr,
char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -1226,9 +1225,9 @@ static ssize_t usb_powershare_high_show(struct device *dev, struct device_attrib
return sysfs_emit(buf, "%d\n", status);
}
-static DEVICE_ATTR_RW(usb_powershare_high);
+static const DEVICE_ATTR_RW(usb_powershare_high);
-static struct attribute *uniwill_attrs[] = {
+static const struct attribute * const uniwill_attrs[] = {
/* Keyboard-related */
&dev_attr_fn_lock.attr,
&dev_attr_super_key_enable.attr,
@@ -1243,7 +1242,7 @@ static struct attribute *uniwill_attrs[] = {
NULL
};
-static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+static umode_t uniwill_attr_is_visible(struct kobject *kobj, const struct attribute *attr, int n)
{
struct device *dev = kobj_to_dev(kobj);
struct uniwill_data *data = dev_get_drvdata(dev);
@@ -1292,11 +1291,11 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
}
static const struct attribute_group uniwill_group = {
- .is_visible = uniwill_attr_is_visible,
- .attrs = uniwill_attrs,
+ .is_visible_const = uniwill_attr_is_visible,
+ .attrs_const = uniwill_attrs,
};
-static const struct attribute_group *uniwill_groups[] = {
+static const struct attribute_group *const uniwill_groups[] = {
&uniwill_group,
NULL
};
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 7/9] platform/x86: uniwill-laptop: Add support for MECHREVO Yilong15Pro
2026-11-10 16:50 [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (5 preceding siblings ...)
2026-11-10 16:50 ` [PATCH v2 6/9] platform/x86: uniwill-laptop: Mark sysfs attributes as const Armin Wolf
@ 2026-11-10 16:50 ` Armin Wolf
2026-11-10 16:50 ` [PATCH v2 8/9] platform/x86: uniwill-laptop: Add MECHREVO JIAOLONG Series-X6xR55xK Armin Wolf
2026-11-10 16:50 ` [PATCH v2 9/9] platform/x86: uniwill-laptop: Add support for XMG EVO 14 (E25) Armin Wolf
8 siblings, 0 replies; 10+ messages in thread
From: Armin Wolf @ 2026-11-10 16:50 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, bifangknt, nicokessler, sre,
linux-pm, wse
A user reported that the MECHREVO Yilong15Pro works with this driver.
Add it to the DMI whitelist to let the driver automatically load on
this device.
Reported-by: Bi Fang <bifangknt@qq.com>
Closes: https://lore.kernel.org/platform-driver-x86/tencent_D521DAA244039DBFC3919D4EFD176E383607@qq.com
Tested-by: Bi Fang <bifangknt@qq.com>
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 24 +++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index fbb704cf6e66..b71e7a73b4ff 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -2781,6 +2781,22 @@ static struct uniwill_device_descriptor machenike_l16p_descriptor __initdata = {
.kbd_led_max_brightness = 4,
};
+static struct uniwill_device_descriptor mechrevo_yilong15pro_descriptor __initdata = {
+ .features = UNIWILL_FEATURE_FN_LOCK |
+ UNIWILL_FEATURE_SUPER_KEY |
+ UNIWILL_FEATURE_BATTERY_CHARGE_MODES |
+ UNIWILL_FEATURE_CPU_TEMP |
+ UNIWILL_FEATURE_GPU_TEMP |
+ UNIWILL_FEATURE_PRIMARY_FAN |
+ UNIWILL_FEATURE_SECONDARY_FAN |
+ UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL |
+ UNIWILL_FEATURE_KEYBOARD_BACKLIGHT |
+ UNIWILL_FEATURE_AC_AUTO_BOOT |
+ UNIWILL_FEATURE_USB_POWERSHARE,
+ .kbd_led_single_color = false,
+ .kbd_led_max_brightness = 4,
+};
+
static struct uniwill_device_descriptor lapqc71a_lapqc71b_descriptor __initdata = {
.features = UNIWILL_FEATURE_SUPER_KEY |
UNIWILL_FEATURE_LIGHTBAR |
@@ -3134,6 +3150,14 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
},
.driver_data = &machenike_l16p_descriptor,
},
+ {
+ .ident = "MECHREVO Yilong15Pro",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MECHREVO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5HG0A"),
+ },
+ .driver_data = &mechrevo_yilong15pro_descriptor,
+ },
{
.ident = "XMG FUSION 15 (L19)",
.matches = {
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 8/9] platform/x86: uniwill-laptop: Add MECHREVO JIAOLONG Series-X6xR55xK
2026-11-10 16:50 [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (6 preceding siblings ...)
2026-11-10 16:50 ` [PATCH v2 7/9] platform/x86: uniwill-laptop: Add support for MECHREVO Yilong15Pro Armin Wolf
@ 2026-11-10 16:50 ` Armin Wolf
2026-11-10 16:50 ` [PATCH v2 9/9] platform/x86: uniwill-laptop: Add support for XMG EVO 14 (E25) Armin Wolf
8 siblings, 0 replies; 10+ messages in thread
From: Armin Wolf @ 2026-11-10 16:50 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, bifangknt, nicokessler, sre,
linux-pm, wse
The MECHREVO JIAOLONG Series-X6xR55xK is similar to the TUXEDO
Stellaris 16 Gen7, but also supports RGB keyboard backlight. Add
the necessary device descriptor for it.
Closes: https://github.com/Wer-Wolf/uniwill-laptop/issues/20
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 24 +++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index b71e7a73b4ff..ab02cd002194 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -2797,6 +2797,22 @@ static struct uniwill_device_descriptor mechrevo_yilong15pro_descriptor __initda
.kbd_led_max_brightness = 4,
};
+static struct uniwill_device_descriptor mechrevo_jiaolong_series_x6xr55xk __initdata = {
+ .features = UNIWILL_FEATURE_FN_LOCK |
+ UNIWILL_FEATURE_SUPER_KEY |
+ UNIWILL_FEATURE_BATTERY_CHARGE_MODES |
+ UNIWILL_FEATURE_CPU_TEMP |
+ UNIWILL_FEATURE_GPU_TEMP |
+ UNIWILL_FEATURE_PRIMARY_FAN |
+ UNIWILL_FEATURE_SECONDARY_FAN |
+ UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL |
+ UNIWILL_FEATURE_KEYBOARD_BACKLIGHT |
+ UNIWILL_FEATURE_AC_AUTO_BOOT |
+ UNIWILL_FEATURE_USB_POWERSHARE,
+ .kbd_led_single_color = false,
+ .kbd_led_max_brightness = 4,
+};
+
static struct uniwill_device_descriptor lapqc71a_lapqc71b_descriptor __initdata = {
.features = UNIWILL_FEATURE_SUPER_KEY |
UNIWILL_FEATURE_LIGHTBAR |
@@ -3158,6 +3174,14 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
},
.driver_data = &mechrevo_yilong15pro_descriptor,
},
+ {
+ .ident = "MECHREVO JIAOLONG Series-X6xR55xK",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MECHREVO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "JIAOLONG Series-X6xR55xK"),
+ },
+ .driver_data = &mechrevo_jiaolong_series_x6xr55xk,
+ },
{
.ident = "XMG FUSION 15 (L19)",
.matches = {
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 9/9] platform/x86: uniwill-laptop: Add support for XMG EVO 14 (E25)
2026-11-10 16:50 [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (7 preceding siblings ...)
2026-11-10 16:50 ` [PATCH v2 8/9] platform/x86: uniwill-laptop: Add MECHREVO JIAOLONG Series-X6xR55xK Armin Wolf
@ 2026-11-10 16:50 ` Armin Wolf
8 siblings, 0 replies; 10+ messages in thread
From: Armin Wolf @ 2026-11-10 16:50 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, bifangknt, nicokessler, sre,
linux-pm, wse
The XMG EVO 14 (E25) uses the same board as the TUXEDO InfinityBook
Pro 14 Gen10 AMD, but contains a different manufacturer string.
Add the necessary DMI entry.
Reported-by: Nico Kessler <nicokessler@icloud.com>
Closes: https://lore.kernel.org/platform-driver-x86/7FEA1980-AFC6-4A6C-84E1-E820B7E6CF3C@icloud.com
Tested-by: Nico Kessler <nicokessler@icloud.com>
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index ab02cd002194..dc99bf8a8568 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -3214,6 +3214,14 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
},
.driver_data = &lapqc71a_lapqc71b_descriptor,
},
+ {
+ .ident = "XMG EVO 14 (E25)",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
+ },
+ .driver_data = &gxxhrxx_gxxmrxx_xxxx4nxx_descriptor,
+ },
{
.ident = "Avell A60 MUV",
.matches = {
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-11-10 16:53 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-10 16:50 [PATCH v2 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
2026-11-10 16:50 ` [PATCH v2 1/9] power: supply: core: Add power_supply_has_property_direct() Armin Wolf
2026-11-10 16:50 ` [PATCH v2 2/9] power: supply: Enable struct power_supply_ext to be construct dynamically Armin Wolf
2026-11-10 16:50 ` [PATCH v2 3/9] platform/x86: uniwill-laptop: Report battery cycle count Armin Wolf
2026-11-10 16:50 ` [PATCH v2 4/9] platform/x86: uniwill-laptop: Expose battery health and cycle count on all devices Armin Wolf
2026-11-10 16:50 ` [PATCH v2 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace Armin Wolf
2026-11-10 16:50 ` [PATCH v2 6/9] platform/x86: uniwill-laptop: Mark sysfs attributes as const Armin Wolf
2026-11-10 16:50 ` [PATCH v2 7/9] platform/x86: uniwill-laptop: Add support for MECHREVO Yilong15Pro Armin Wolf
2026-11-10 16:50 ` [PATCH v2 8/9] platform/x86: uniwill-laptop: Add MECHREVO JIAOLONG Series-X6xR55xK Armin Wolf
2026-11-10 16:50 ` [PATCH v2 9/9] platform/x86: uniwill-laptop: Add support for XMG EVO 14 (E25) Armin Wolf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®