From: Chris Taraszka <chris@miget.com>
To: "Hans de Goede" <hansg@kernel.org>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
Cc: platform-driver-x86@vger.kernel.org,
linux-kernel@vger.kernel.org, Mingyou Chen <qby140326@gmail.com>,
Ilya Gladyshev <ilya.gladyshev@linux.dev>,
Armin Wolf <W_Armin@gmx.de>, KentoNion <kento@kekto.ru>,
Matias Civadda <matias.civadda2342001@gmail.com>,
Chris Taraszka <chris@miget.com>
Subject: [PATCH v3 3/4] platform/x86: bitland-mifs-wmi: Support a separate profile value on battery
Date: Sun, 1 Nov 2026 17:18:13 +0100 [thread overview]
Message-ID: <20261101161814.1325847-4-chris@miget.com> (raw)
In-Reply-To: <20261101161814.1325847-1-chris@miget.com>
The Xiaomi Book Pro 14 firmware uses different SystemPerMode values for
performance depending on the power source: 0x04 on AC and 0x03 on
battery, both with a 50-58 W sustained power limit. Its DTT tables have
no battery entry for 0x04, and BIOS 0707 refuses 0x04 on battery, so
the driver currently refuses performance on battery.
Let a profile entry be marked for battery use. It is set in place of
the AC entry for the same profile while the system runs on battery,
without the AC check. The firmware does not change the mode when the
power source changes, so re-apply the current profile from an ACPI AC
notifier, taking the AC state from the event. A mutex keeps this from
racing with profile changes from userspace.
Mark 0x03 as the battery value for performance on the Xiaomi Book
Pro 14.
Suggested-by: KentoNion <kento@kekto.ru>
Signed-off-by: Chris Taraszka <chris@miget.com>
---
Notes:
Tested with ftrace kprobes on the AC notifier and on the WMI calls:
AC, performance (0x04), unplug: the notifier sets 0x03 within 1 ms
battery, performance: set 0x03, PL1 58 W
battery, performance (0x03), plug in: the notifier sets 0x04
s2idle from performance on AC: resume restores 0x04
Battery class events are ignored. Here Omarchy also switches to its
saved per-source profile about a second later, which goes through
laptop_profile_set() after the notifier.
drivers/platform/x86/bitland-mifs-wmi.c | 122 +++++++++++++++++++++---
1 file changed, 108 insertions(+), 14 deletions(-)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 0891dcc1e9b4..4d02cd9e8a6b 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -91,6 +91,7 @@ struct bitland_profile_entry {
enum platform_profile_option profile;
u8 wmi_val;
bool no_set;
+ bool battery; /* Set in place of the AC entry while on battery */
};
struct bitland_mifs_quirks {
@@ -118,7 +119,7 @@ static const struct bitland_profile_entry tm2424_profile_entries[] = {
{ PLATFORM_PROFILE_LOW_POWER, 0x0a, true },
{ PLATFORM_PROFILE_BALANCED, 0x09 },
{ PLATFORM_PROFILE_PERFORMANCE, 0x04 },
- { PLATFORM_PROFILE_PERFORMANCE, 0x03, true },
+ { PLATFORM_PROFILE_PERFORMANCE, 0x03, .battery = true },
};
static const struct bitland_mifs_quirks tm2424_quirks = {
@@ -227,8 +228,10 @@ struct bitland_fan_notify_data {
struct bitland_mifs_wmi_data {
struct wmi_device *wdev;
struct mutex lock; /* Protects WMI calls */
+ struct mutex profile_lock; /* Serializes profile changes */
struct led_classdev kbd_led;
struct notifier_block notifier;
+ struct notifier_block ac_notifier;
struct input_dev *input_dev;
struct device *hwmon_dev;
struct device *pp_dev;
@@ -350,34 +353,108 @@ static int bitland_pp_check_capability(struct bitland_mifs_wmi_data *data)
return 0;
}
-static int laptop_profile_set(struct device *dev,
- enum platform_profile_option profile)
+static const struct bitland_profile_entry *
+bitland_profile_set_entry(const struct bitland_mifs_quirks *quirks,
+ enum platform_profile_option profile, bool on_battery)
+{
+ const struct bitland_profile_entry *entry = NULL;
+ size_t i;
+
+ for (i = 0; i < quirks->num_profile_entries; i++) {
+ const struct bitland_profile_entry *e = &quirks->profile_entries[i];
+
+ if (e->profile != profile || e->no_set)
+ continue;
+
+ if (e->battery && on_battery)
+ return e;
+
+ if (!e->battery && !entry)
+ entry = e;
+ }
+
+ return entry;
+}
+
+static int bitland_profile_set(struct bitland_mifs_wmi_data *data,
+ enum platform_profile_option profile,
+ bool on_battery)
{
- struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
- const struct bitland_mifs_quirks *quirks = data->quirks;
struct bitland_mifs_input input = {
.operation = cpu_to_le16(WMI_METHOD_SET),
.function = cpu_to_le16(WMI_FN_SYSTEM_PER_MODE),
};
- size_t i;
+ const struct bitland_profile_entry *entry;
int ret;
- if (profile == PLATFORM_PROFILE_PERFORMANCE ||
- profile == PLATFORM_PROFILE_BALANCED_PERFORMANCE) {
+ entry = bitland_profile_set_entry(data->quirks, profile, on_battery);
+ if (!entry)
+ return -EOPNOTSUPP;
+
+ if (!entry->battery &&
+ (profile == PLATFORM_PROFILE_PERFORMANCE ||
+ profile == PLATFORM_PROFILE_BALANCED_PERFORMANCE)) {
ret = bitland_pp_check_capability(data);
if (ret)
return ret;
}
+ input.payload[0] = entry->wmi_val;
+
+ return bitland_mifs_wmi_call(data, &input, NULL);
+}
+
+static int laptop_profile_set(struct device *dev,
+ enum platform_profile_option profile)
+{
+ struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+
+ guard(mutex)(&data->profile_lock);
+
+ return bitland_profile_set(data, profile,
+ !power_supply_is_system_supplied());
+}
+
+static int bitland_ac_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct bitland_mifs_wmi_data *drv_data =
+ container_of(nb, struct bitland_mifs_wmi_data, ac_notifier);
+ struct acpi_bus_event *event = data;
+ enum platform_profile_option profile;
+ int ret;
+
+ if (strcmp(event->device_class, ACPI_AC_CLASS))
+ return NOTIFY_DONE;
+
+ guard(mutex)(&drv_data->profile_lock);
+
+ /* Switch to the AC or battery value of the current profile */
+ ret = laptop_profile_get(drv_data->pp_dev, &profile);
+ if (!ret)
+ ret = bitland_profile_set(drv_data, profile, !event->data);
+ if (ret)
+ dev_warn(&drv_data->wdev->dev,
+ "Failed to update platform profile on AC change: %d\n", ret);
+
+ return NOTIFY_DONE;
+}
+
+static void bitland_ac_notifier_unregister(void *data)
+{
+ unregister_acpi_notifier(data);
+}
+
+static bool bitland_has_battery_entries(const struct bitland_mifs_quirks *quirks)
+{
+ size_t i;
+
for (i = 0; i < quirks->num_profile_entries; i++) {
- if (quirks->profile_entries[i].profile == profile &&
- !quirks->profile_entries[i].no_set) {
- input.payload[0] = quirks->profile_entries[i].wmi_val;
- return bitland_mifs_wmi_call(data, &input, NULL);
- }
+ if (quirks->profile_entries[i].battery)
+ return true;
}
- return -EOPNOTSUPP;
+ return false;
}
static int platform_profile_probe(void *drvdata, unsigned long *choices)
@@ -826,6 +903,10 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
if (ret)
return ret;
+ ret = devm_mutex_init(&wdev->dev, &drv_data->profile_lock);
+ if (ret)
+ return ret;
+
dev_set_drvdata(&wdev->dev, drv_data);
drv_data->quirks = &default_quirks;
@@ -858,6 +939,19 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
if (IS_ERR(drv_data->pp_dev))
return PTR_ERR(drv_data->pp_dev);
+ if (bitland_has_battery_entries(drv_data->quirks)) {
+ drv_data->ac_notifier.notifier_call = bitland_ac_notify;
+ ret = register_acpi_notifier(&drv_data->ac_notifier);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(&wdev->dev,
+ bitland_ac_notifier_unregister,
+ &drv_data->ac_notifier);
+ if (ret)
+ return ret;
+ }
+
/* Register hwmon */
drv_data->hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev,
"bitland_mifs",
--
2.56.0
next prev parent reply other threads:[~2026-11-01 16:18 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-01 16:18 [PATCH v3 0/4] platform/x86: bitland-mifs-wmi: Xiaomi Book Pro 14 support Chris Taraszka
2026-11-01 16:18 ` [PATCH v3 1/4] platform/x86: bitland-mifs-wmi: Add Xiaomi Book Pro 14 quirk Chris Taraszka
2026-11-01 16:18 ` [PATCH v3 2/4] platform/x86: bitland-mifs-wmi: Don't fail suspend or resume on profile errors Chris Taraszka
2026-11-01 16:18 ` Chris Taraszka [this message]
2026-11-01 16:18 ` [PATCH v3 4/4] platform/x86: bitland-mifs-wmi: Cycle the platform profile on Fn+K Chris Taraszka
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261101161814.1325847-4-chris@miget.com \
--to=chris@miget.com \
--cc=W_Armin@gmx.de \
--cc=hansg@kernel.org \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=ilya.gladyshev@linux.dev \
--cc=kento@kekto.ru \
--cc=linux-kernel@vger.kernel.org \
--cc=matias.civadda2342001@gmail.com \
--cc=platform-driver-x86@vger.kernel.org \
--cc=qby140326@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®