mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] platform/x86: bitland-mifs-wmi: Fix TM2107 profile handling
@ 2026-09-28  6:49 TuteMthCD
  2026-09-28 12:14 ` Ilpo Järvinen
  0 siblings, 1 reply; 2+ messages in thread
From: TuteMthCD @ 2026-09-28  6:49 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen; +Cc: W_Armin, platform-driver-x86, linux-kernel

On the TIMI Redmi Book Pro 14 2022 (TM2107), the MIFS WMI response uses
a different layout from the one currently assumed by the driver.
This causes profile reads to fail or report an incorrect profile.

The response contains a 30-byte OutData field followed by a 16-bit
Reserved field. On this model, the profile value is returned in
OutData[2], while the return code is stored in the trailing 16-bit
field.

Selecting the modes in GCommandCenter and reading the WMI response
on this machine yielded the following values:

0: performance
1: balanced
2: quiet

Handle this model through DMI-specific driver_data, normalize its
response layout, and map its profile values correctly. Expose only
the three supported profiles.

Require external power for performance mode, including the original
USB-C charger, matching the behavior observed in GCommandCenter.
Skip the adapter-type query on this model.

Build-tested against pdx86/for-next with W=1. Built and tested on
Linux 7.2.7-zen1-1-zen on a Redmi Book Pro 14 2022 (TM2107).
Verified profile switching, performance selection with the USB-C
charger connected, and rejection while running on battery.

Link: https://lkml.iu.edu/2608.2/00163.html
Fixes: dc1ec4fa86b2 ("platform/x86: bitland-mifs-wmi: Add new Bitland MIFS WMI driver")
Assisted-by: LLM
Signed-off-by: TuteMthCD <matias.civadda2342001@gmail.com>
---
Changes since v1:
- Rebased on pdx86/for-next.
- Use a generic DMI table with per-model driver_data.
- Add the DMI dependency.
- Normalize the response layout before validating the return code
  and function ID.
- Correct the profile mapping using observations from GCommandCenter.
- Expose only the three supported profiles.

The previous version was mistakenly based on the commit used by my
local Linux distribution instead of pdx86/for-next. Sorry for the
confusion.

I also collected WMI response data on Windows while switching profiles
in GCommandCenter. I can share those results if useful.

v1: https://lore.kernel.org/20260925032001.111062-1-matias.civadda2342001@gmail.com/

 drivers/platform/x86/Kconfig            |   1 +
 drivers/platform/x86/bitland-mifs-wmi.c | 135 +++++++++++++++++-------
 2 files changed, 97 insertions(+), 39 deletions(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 45f15f93afa7..e3351ee1dd43 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -116,6 +116,7 @@ config GIGABYTE_WMI
 config BITLAND_MIFS_WMI
 	tristate "Bitland MIFS (MiInterface) WMI driver"
 	depends on ACPI_WMI
+	depends on DMI
 	depends on HWMON
 	depends on INPUT
 	depends on LEDS_CLASS
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index dd1648b7de77..29e365b54c84 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -14,6 +14,7 @@
 #include <linux/dev_printk.h>
 #include <linux/device.h>
 #include <linux/device/devres.h>
+#include <linux/dmi.h>
 #include <linux/err.h>
 #include <linux/hwmon.h>
 #include <linux/init.h>
@@ -131,6 +132,58 @@ struct bitland_mifs_output {
 	u8 data[28];
 } __packed;
 
+/* TM2107 places the return code after the function ID and payload. */
+struct bitland_mifs_output_tm2107 {
+	__le16 function;
+	u8 data[28];
+	__le16 return_code;
+} __packed;
+
+struct bitland_mifs_quirks {
+	const enum platform_profile_option *profiles;
+	size_t num_profiles;
+	bool return_code_at_end;
+	bool skip_ac_type_check;
+};
+
+static const enum platform_profile_option bitland_profiles[] = {
+	[WMI_PP_BALANCED] = PLATFORM_PROFILE_BALANCED,
+	[WMI_PP_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE,
+	[WMI_PP_QUIET] = PLATFORM_PROFILE_LOW_POWER,
+	[WMI_PP_FULL_SPEED] = PLATFORM_PROFILE_PERFORMANCE,
+};
+
+/* Values observed after selecting each mode in GCommandCenter. */
+static const enum platform_profile_option tm2107_profiles[] = {
+	[0] = PLATFORM_PROFILE_PERFORMANCE,
+	[1] = PLATFORM_PROFILE_BALANCED,
+	[2] = PLATFORM_PROFILE_LOW_POWER,
+};
+
+static const struct bitland_mifs_quirks bitland_default_quirks = {
+	.profiles = bitland_profiles,
+	.num_profiles = ARRAY_SIZE(bitland_profiles),
+};
+
+static const struct bitland_mifs_quirks bitland_tm2107_quirks = {
+	.profiles = tm2107_profiles,
+	.num_profiles = ARRAY_SIZE(tm2107_profiles),
+	.return_code_at_end = true,
+	.skip_ac_type_check = true,
+};
+
+static const struct dmi_system_id bitland_mifs_dmi_table[] = {
+	{
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TIMI"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Redmi Book Pro 14 2022"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TM2107"),
+		},
+		.driver_data = (void *)&bitland_tm2107_quirks,
+	},
+	{}
+};
+
 struct bitland_mifs_event {
 	u8 event_type;
 	u8 event_id;
@@ -154,6 +207,7 @@ struct bitland_fan_notify_data {
 
 struct bitland_mifs_wmi_data {
 	struct wmi_device *wdev;
+	const struct bitland_mifs_quirks *quirks;
 	struct mutex lock;		/* Protects WMI calls */
 	struct led_classdev kbd_led;
 	struct notifier_block notifier;
@@ -180,6 +234,17 @@ static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
 
 	struct bitland_mifs_output *result __free(kfree) = out_buf.data;
 
+	if (data->quirks->return_code_at_end) {
+		const struct bitland_mifs_output_tm2107 *raw = out_buf.data;
+		struct bitland_mifs_output normalized = {
+			.return_code = raw->return_code,
+			.function = raw->function,
+		};
+
+		memcpy(normalized.data, raw->data, sizeof(normalized.data));
+		*result = normalized;
+	}
+
 	switch (le16_to_cpu(result->return_code)) {
 	case WMI_RETURN_CODE_SUCCESS:
 		break;
@@ -202,6 +267,7 @@ static int laptop_profile_get(struct device *dev,
 			      enum platform_profile_option *profile)
 {
 	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_GET),
 		.function = cpu_to_le16(WMI_FN_SYSTEM_PER_MODE),
@@ -213,22 +279,10 @@ static int laptop_profile_get(struct device *dev,
 	if (ret)
 		return ret;
 
-	switch (result.data[0]) {
-	case WMI_PP_BALANCED:
-		*profile = PLATFORM_PROFILE_BALANCED;
-		break;
-	case WMI_PP_PERFORMANCE:
-		*profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
-		break;
-	case WMI_PP_QUIET:
-		*profile = PLATFORM_PROFILE_LOW_POWER;
-		break;
-	case WMI_PP_FULL_SPEED:
-		*profile = PLATFORM_PROFILE_PERFORMANCE;
-		break;
-	default:
+	if (result.data[0] >= quirks->num_profiles)
 		return -EINVAL;
-	}
+
+	*profile = quirks->profiles[result.data[0]];
 	return 0;
 }
 
@@ -241,6 +295,10 @@ static int bitland_check_performance_capability(struct bitland_mifs_wmi_data *da
 	struct bitland_mifs_output output;
 	int ret;
 
+	/* TM2107 accepts its USB-C charger, without an AC type query. */
+	if (data->quirks->skip_ac_type_check)
+		return power_supply_is_system_supplied() > 0 ? 0 : -EOPNOTSUPP;
+
 	/* Full-speed/performance mode requires DC power (not USB-C) */
 	if (!power_supply_is_system_supplied())
 		return -EOPNOTSUPP;
@@ -263,47 +321,40 @@ static int laptop_profile_set(struct device *dev,
 			      enum platform_profile_option profile)
 {
 	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;
 	int ret;
-	u8 val;
 
-	switch (profile) {
-	case PLATFORM_PROFILE_LOW_POWER:
-		val = WMI_PP_QUIET;
-		break;
-	case PLATFORM_PROFILE_BALANCED:
-		val = WMI_PP_BALANCED;
-		break;
-	case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
-		ret = bitland_check_performance_capability(data);
-		if (ret)
-			return ret;
-		val = WMI_PP_PERFORMANCE;
-		break;
-	case PLATFORM_PROFILE_PERFORMANCE:
+	for (i = 0; i < quirks->num_profiles; i++) {
+		if (profile == quirks->profiles[i])
+			break;
+	}
+	if (i == quirks->num_profiles)
+		return -EOPNOTSUPP;
+
+	if (profile == PLATFORM_PROFILE_BALANCED_PERFORMANCE ||
+	    profile == PLATFORM_PROFILE_PERFORMANCE) {
 		ret = bitland_check_performance_capability(data);
 		if (ret)
 			return ret;
-		val = WMI_PP_FULL_SPEED;
-		break;
-	default:
-		return -EOPNOTSUPP;
 	}
 
-	input.payload[0] = val;
+	input.payload[0] = i;
 
 	return bitland_mifs_wmi_call(data, &input, NULL);
 }
 
 static int platform_profile_probe(void *drvdata, unsigned long *choices)
 {
-	set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
-	set_bit(PLATFORM_PROFILE_BALANCED, choices);
-	set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices);
-	set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
+	struct bitland_mifs_wmi_data *data = drvdata;
+	size_t i;
+
+	for (i = 0; i < data->quirks->num_profiles; i++)
+		set_bit(data->quirks->profiles[i], choices);
 
 	return 0;
 }
@@ -659,6 +710,7 @@ static int bitland_notifier_callback(struct notifier_block *nb,
 static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
 {
 	struct bitland_mifs_wmi_data *drv_data;
+	const struct dmi_system_id *dmi_id;
 	enum bitland_wmi_device_type dev_type =
 		(enum bitland_wmi_device_type)(unsigned long)context;
 	struct led_init_data init_data = {
@@ -674,6 +726,11 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
 
 	drv_data->wdev = wdev;
 
+	drv_data->quirks = &bitland_default_quirks;
+	dmi_id = dmi_first_match(bitland_mifs_dmi_table);
+	if (dmi_id)
+		drv_data->quirks = dmi_id->driver_data;
+
 	ret = devm_mutex_init(&wdev->dev, &drv_data->lock);
 	if (ret)
 		return ret;

base-commit: f475845eaf3d749114a63270bf2efea459e14dd2
-- 
2.55.0


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

end of thread, other threads:[~2026-09-28 12:14 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-28  6:49 [PATCH v2] platform/x86: bitland-mifs-wmi: Fix TM2107 profile handling TuteMthCD
2026-09-28 12:14 ` Ilpo Järvinen

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®