* [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support
@ 2026-11-10 0:06 Armin Wolf
2026-11-10 0:06 ` [PATCH 1/9] power: supply: core: Add power_supply_has_property_direct() Armin Wolf
` (8 more replies)
0 siblings, 9 replies; 11+ messages in thread
From: Armin Wolf @ 2026-11-10 0:06 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 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
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 | 265 ++++++++++++------
drivers/power/supply/power_supply_core.c | 26 +-
include/linux/power_supply.h | 3 +-
4 files changed, 218 insertions(+), 87 deletions(-)
--
2.56.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/9] power: supply: core: Add power_supply_has_property_direct()
2026-11-10 0:06 [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
@ 2026-11-10 0:06 ` Armin Wolf
2026-11-10 0:06 ` [PATCH 2/9] power: supply: Enable struct power_supply_ext to be construct dynamically Armin Wolf
` (7 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Armin Wolf @ 2026-11-10 0:06 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] 11+ messages in thread
* [PATCH 2/9] power: supply: Enable struct power_supply_ext to be construct dynamically
2026-11-10 0:06 [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
2026-11-10 0:06 ` [PATCH 1/9] power: supply: core: Add power_supply_has_property_direct() Armin Wolf
@ 2026-11-10 0:06 ` Armin Wolf
2026-11-10 0:06 ` [PATCH 3/9] platform/x86: uniwill-laptop: Report battery cycle count Armin Wolf
` (6 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Armin Wolf @ 2026-11-10 0:06 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] 11+ messages in thread
* [PATCH 3/9] platform/x86: uniwill-laptop: Report battery cycle count
2026-11-10 0:06 [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
2026-11-10 0:06 ` [PATCH 1/9] power: supply: core: Add power_supply_has_property_direct() Armin Wolf
2026-11-10 0:06 ` [PATCH 2/9] power: supply: Enable struct power_supply_ext to be construct dynamically Armin Wolf
@ 2026-11-10 0:06 ` Armin Wolf
2026-11-10 0:06 ` [PATCH 4/9] platform/x86: uniwill-laptop: Expose battery health and cycle count on all devices Armin Wolf
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Armin Wolf @ 2026-11-10 0:06 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] 11+ messages in thread
* [PATCH 4/9] platform/x86: uniwill-laptop: Expose battery health and cycle count on all devices
2026-11-10 0:06 [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (2 preceding siblings ...)
2026-11-10 0:06 ` [PATCH 3/9] platform/x86: uniwill-laptop: Report battery cycle count Armin Wolf
@ 2026-11-10 0:06 ` Armin Wolf
2026-11-10 0:06 ` [PATCH 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace Armin Wolf
` (4 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Armin Wolf @ 2026-11-10 0:06 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] 11+ messages in thread
* [PATCH 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace
2026-11-10 0:06 [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (3 preceding siblings ...)
2026-11-10 0:06 ` [PATCH 4/9] platform/x86: uniwill-laptop: Expose battery health and cycle count on all devices Armin Wolf
@ 2026-11-10 0:06 ` Armin Wolf
2026-11-10 11:13 ` kernel test robot
2026-11-10 0:06 ` [PATCH 6/9] platform/x86: uniwill-laptop: Mark sysfs attributes as const Armin Wolf
` (3 subsequent siblings)
8 siblings, 1 reply; 11+ messages in thread
From: Armin Wolf @ 2026-11-10 0:06 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 | 44 +++++++++++++++++--
2 files changed, 51 insertions(+), 4 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..3d59b9a0f5bf 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,16 +2140,18 @@ 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;
- }
+ if (ret < 0)
+ goto err_remove;
guard(mutex)(&data->battery_lock);
@@ -2137,6 +2159,14 @@ static int uniwill_add_battery(struct power_supply *battery, struct acpi_battery
list_add(&entry->head, &data->batteries);
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] 11+ messages in thread
* [PATCH 6/9] platform/x86: uniwill-laptop: Mark sysfs attributes as const
2026-11-10 0:06 [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (4 preceding siblings ...)
2026-11-10 0:06 ` [PATCH 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace Armin Wolf
@ 2026-11-10 0:06 ` Armin Wolf
2026-11-10 0:06 ` [PATCH 7/9] platform/x86: uniwill-laptop: Add support for MECHREVO Yilong15Pro Armin Wolf
` (2 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Armin Wolf @ 2026-11-10 0:06 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 3d59b9a0f5bf..a987fb310b81 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] 11+ messages in thread
* [PATCH 7/9] platform/x86: uniwill-laptop: Add support for MECHREVO Yilong15Pro
2026-11-10 0:06 [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (5 preceding siblings ...)
2026-11-10 0:06 ` [PATCH 6/9] platform/x86: uniwill-laptop: Mark sysfs attributes as const Armin Wolf
@ 2026-11-10 0:06 ` Armin Wolf
2026-11-10 0:06 ` [PATCH 8/9] platform/x86: uniwill-laptop: Add MECHREVO JIAOLONG Series-X6xR55xK Armin Wolf
2026-11-10 0:06 ` [PATCH 9/9] platform/x86: uniwill-laptop: Add support for XMG EVO 14 (E25) Armin Wolf
8 siblings, 0 replies; 11+ messages in thread
From: Armin Wolf @ 2026-11-10 0:06 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 a987fb310b81..10c26822a607 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] 11+ messages in thread
* [PATCH 8/9] platform/x86: uniwill-laptop: Add MECHREVO JIAOLONG Series-X6xR55xK
2026-11-10 0:06 [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (6 preceding siblings ...)
2026-11-10 0:06 ` [PATCH 7/9] platform/x86: uniwill-laptop: Add support for MECHREVO Yilong15Pro Armin Wolf
@ 2026-11-10 0:06 ` Armin Wolf
2026-11-10 0:06 ` [PATCH 9/9] platform/x86: uniwill-laptop: Add support for XMG EVO 14 (E25) Armin Wolf
8 siblings, 0 replies; 11+ messages in thread
From: Armin Wolf @ 2026-11-10 0:06 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 10c26822a607..6b0138246599 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] 11+ messages in thread
* [PATCH 9/9] platform/x86: uniwill-laptop: Add support for XMG EVO 14 (E25)
2026-11-10 0:06 [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
` (7 preceding siblings ...)
2026-11-10 0:06 ` [PATCH 8/9] platform/x86: uniwill-laptop: Add MECHREVO JIAOLONG Series-X6xR55xK Armin Wolf
@ 2026-11-10 0:06 ` Armin Wolf
8 siblings, 0 replies; 11+ messages in thread
From: Armin Wolf @ 2026-11-10 0:06 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 6b0138246599..610ffb8d76bd 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] 11+ messages in thread
* Re: [PATCH 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace
2026-11-10 0:06 ` [PATCH 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace Armin Wolf
@ 2026-11-10 11:13 ` kernel test robot
0 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-11-10 11:13 UTC (permalink / raw)
To: Armin Wolf, hansg, ilpo.jarvinen
Cc: llvm, oe-kbuild-all, platform-driver-x86, linux-kernel,
bifangknt, nicokessler, sre, linux-pm, wse
Hi Armin,
kernel test robot noticed the following build errors:
[auto build test ERROR on sre-power-supply/for-next]
[also build test ERROR on linus/master v7.4-rc2 next-20261109]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Armin-Wolf/power-supply-core-Add-power_supply_has_property_direct/20261110-010643
base: https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git for-next
patch link: https://lore.kernel.org/r/20261110001725.851443-6-W_Armin%40gmx.de
patch subject: [PATCH 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace
config: i386-randconfig-1009-20261110 (https://download.01.org/0day-ci/archive/20261110/202611101928.MbCyLNXk-lkp@intel.com/config)
compiler: clang version 22.1.8 (https://github.com/llvm/llvm-project ca7933e47d3a3451d81e72ac174dcb5aa28b59d1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261110/202611101928.MbCyLNXk-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202611101928.MbCyLNXk-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/platform/x86/uniwill/uniwill-acpi.c:2148:3: error: cannot jump from this goto statement to its label
2148 | goto err_remove;
| ^
drivers/platform/x86/uniwill/uniwill-acpi.c:2150:2: note: jump bypasses initialization of variable with __attribute__((cleanup))
2150 | guard(mutex)(&data->battery_lock);
| ^
include/linux/cleanup.h:416:2: note: expanded from macro 'guard'
416 | CLASS(_name, __UNIQUE_ID(guard))
| ^
include/linux/cleanup.h:299:3: note: expanded from macro 'CLASS'
299 | class_##_name##_constructor
| ^
<scratch space>:19:1: note: expanded from here
19 | class_mutex_constructor
| ^
note: (skipping 3 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
include/linux/compiler_types.h:16:23: note: expanded from macro '__PASTE'
16 | #define __PASTE(a, b) ___PASTE(a, b)
| ^
include/linux/compiler_types.h:15:24: note: expanded from macro '___PASTE'
15 | #define ___PASTE(a, b) a##b
| ^
<scratch space>:25:1: note: expanded from here
25 | __UNIQUE_ID_unlock_362
| ^
drivers/platform/x86/uniwill/uniwill-acpi.c:2150:2: note: jump bypasses initialization of variable with __attribute__((cleanup))
include/linux/cleanup.h:416:15: note: expanded from macro 'guard'
416 | CLASS(_name, __UNIQUE_ID(guard))
| ^
include/linux/compiler.h:165:2: note: expanded from macro '__UNIQUE_ID'
165 | __PASTE(__UNIQUE_ID_, \
| ^
include/linux/compiler_types.h:16:23: note: expanded from macro '__PASTE'
16 | #define __PASTE(a, b) ___PASTE(a, b)
| ^
include/linux/compiler_types.h:15:24: note: expanded from macro '___PASTE'
15 | #define ___PASTE(a, b) a##b
| ^
<scratch space>:13:1: note: expanded from here
13 | __UNIQUE_ID_guard_361
| ^
drivers/platform/x86/uniwill/uniwill-acpi.c:2139:3: error: cannot jump from this goto statement to its label
2139 | goto err_free;
| ^
drivers/platform/x86/uniwill/uniwill-acpi.c:2150:2: note: jump bypasses initialization of variable with __attribute__((cleanup))
2150 | guard(mutex)(&data->battery_lock);
| ^
include/linux/cleanup.h:416:2: note: expanded from macro 'guard'
416 | CLASS(_name, __UNIQUE_ID(guard))
| ^
include/linux/cleanup.h:299:3: note: expanded from macro 'CLASS'
299 | class_##_name##_constructor
| ^
<scratch space>:19:1: note: expanded from here
19 | class_mutex_constructor
| ^
note: (skipping 3 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
include/linux/compiler_types.h:16:23: note: expanded from macro '__PASTE'
16 | #define __PASTE(a, b) ___PASTE(a, b)
| ^
include/linux/compiler_types.h:15:24: note: expanded from macro '___PASTE'
15 | #define ___PASTE(a, b) a##b
| ^
<scratch space>:25:1: note: expanded from here
25 | __UNIQUE_ID_unlock_362
| ^
drivers/platform/x86/uniwill/uniwill-acpi.c:2150:2: note: jump bypasses initialization of variable with __attribute__((cleanup))
include/linux/cleanup.h:416:15: note: expanded from macro 'guard'
416 | CLASS(_name, __UNIQUE_ID(guard))
| ^
include/linux/compiler.h:165:2: note: expanded from macro '__UNIQUE_ID'
165 | __PASTE(__UNIQUE_ID_, \
| ^
include/linux/compiler_types.h:16:23: note: expanded from macro '__PASTE'
16 | #define __PASTE(a, b) ___PASTE(a, b)
| ^
include/linux/compiler_types.h:15:24: note: expanded from macro '___PASTE'
15 | #define ___PASTE(a, b) a##b
| ^
<scratch space>:13:1: note: expanded from here
13 | __UNIQUE_ID_guard_361
| ^
2 errors generated.
vim +2148 drivers/platform/x86/uniwill/uniwill-acpi.c
2125
2126 static int uniwill_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
2127 {
2128 struct uniwill_data *data = container_of(hook, struct uniwill_data, hook);
2129 struct uniwill_battery_entry *entry;
2130 const struct power_supply_ext *ext;
2131 int ret;
2132
2133 entry = kzalloc_obj(*entry);
2134 if (!entry)
2135 return -ENOMEM;
2136
2137 ret = device_create_file(&battery->dev, &data->charge_full_raw_attr);
2138 if (ret < 0)
2139 goto err_free;
2140
2141 if (power_supply_has_property_direct(battery, POWER_SUPPLY_PROP_CYCLE_COUNT))
2142 ext = &data->standard_extension;
2143 else
2144 ext = &data->cycle_count_extension;
2145
2146 ret = power_supply_register_extension(battery, ext, data->dev, data);
2147 if (ret < 0)
> 2148 goto err_remove;
2149
2150 guard(mutex)(&data->battery_lock);
2151
2152 entry->battery = battery;
2153 list_add(&entry->head, &data->batteries);
2154
2155 return 0;
2156
2157 err_remove:
2158 device_remove_file(&battery->dev, &data->charge_full_raw_attr);
2159
2160 err_free:
2161 kfree(entry);
2162
2163 return ret;
2164 }
2165
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-11-10 11:13 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-10 0:06 [PATCH 0/9] platform/x86: uniwill-laptop: Complete battery support Armin Wolf
2026-11-10 0:06 ` [PATCH 1/9] power: supply: core: Add power_supply_has_property_direct() Armin Wolf
2026-11-10 0:06 ` [PATCH 2/9] power: supply: Enable struct power_supply_ext to be construct dynamically Armin Wolf
2026-11-10 0:06 ` [PATCH 3/9] platform/x86: uniwill-laptop: Report battery cycle count Armin Wolf
2026-11-10 0:06 ` [PATCH 4/9] platform/x86: uniwill-laptop: Expose battery health and cycle count on all devices Armin Wolf
2026-11-10 0:06 ` [PATCH 5/9] platform/x86: uniwill-laptop: Expose raw battery capacity to userspace Armin Wolf
2026-11-10 11:13 ` kernel test robot
2026-11-10 0:06 ` [PATCH 6/9] platform/x86: uniwill-laptop: Mark sysfs attributes as const Armin Wolf
2026-11-10 0:06 ` [PATCH 7/9] platform/x86: uniwill-laptop: Add support for MECHREVO Yilong15Pro Armin Wolf
2026-11-10 0:06 ` [PATCH 8/9] platform/x86: uniwill-laptop: Add MECHREVO JIAOLONG Series-X6xR55xK Armin Wolf
2026-11-10 0:06 ` [PATCH 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®