Re: [PATCH v5 6/6] platform/x86: bitland-mifs-wmi: Add Redmi laptop support
Miloš Vlku <[email protected]>
| Newsgroups | org.kernel.vger.platform-driver-x86,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CAObHBTxSTzGSuN=8a+PQs7Khxv+_JMenf2a4j8me-L0ksDnXXQ@mail.gmail.com> |
> + {
> + /* Redmi Book series */
> + .matches = {
> + DMI_MATCH(DMI_SYS_VENDOR, "Redmi"),
> + },
> + .driver_data = (void *)&redmi_book_ops,
> + },
> + {
> + /* Xiaomi Book series */
> + .matches = {
> + DMI_MATCH(DMI_SYS_VENDOR, "TIMI"),
> + },
> + .driver_data = (void *)&redmi_book_ops,
> + },
Neither entry matches my machine. I have a Redmi Book Pro 14 2024, and
it reports:
DMI_SYS_VENDOR XIAOMI
DMI_BOARD_NAME TM2307
DMI_PRODUCT_NAME Redmi Book Pro 14 2024
Since DMI_MATCH() is a substring test, neither "Redmi" nor "TIMI"
matches "XIAOMI", so dmi_first_match() returns NULL and data->ops stays
at &bitland_ops. The series has no effect on this model.
A board-name match would cover it:
{
/* Redmi Book Pro 14 2024 */
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "TM2307"),
},
.driver_data = (void *)&redmi_book_ops,
},
I don't know how widely the "XIAOMI" vendor string is used across the
range, so matching DMI_SYS_VENDOR "XIAOMI" may cover more machines at
once if that encoding applies to all of them.
Thanks,
Milos
On Sun, Aug 16, 2026 at 12:08 PM Mingyou Chen <[email protected]> wrote:
>
> Redmi laptops (Redmi Book and Redmi G series) use the same MIFS WMI
> interface but encode the performance mode values of
> WMI_FN_SYSTEM_PER_MODE differently, as reverse engineered from the
> Windows GCommandCenter application:
>
> 0 = performance, 1 = balanced, 2 = quiet, 4 = full speed
>
> Add "Redmi Book" and "Redmi G" ops entries selected via DMI:
> - Redmi G (board TM2135/TM2137): the full-speed mode is available
> - Redmi Book/Xiaomi Book: no full-speed mode
> - The performance modes only require AC power (any source); the
> barrel-jack requirement is Bitland-specific
>
> The GCommandCenter application further showed that:
> - the CPU power sensor (WMI_FN_CPU_POWER) is only available on Redmi
> machines, gate the hwmon power channel on the ops table
> - the refresh-rate-toggle quirk in the CPU fan speed event is
> Redmi-specific, gate it on the ops table instead of applying it
> unconditionally
>
> Also add Redmi support for Fn lock and touchpad lock control
> (WMI_FN_FN_LOCK / WMI_FN_TP_LOCK sysfs attributes), keyboard type
> detection (hide the RGB kb_mode attribute on white-only backlit
> keyboards) and hotkeys (airplane mode -> KEY_RFKILL, ignore the
> lock-state and keyboard mode indicator events).
>
> The sysfs attribute group is now registered in probe (instead of via
> dev_groups) so that the is_visible callback can access the probe
> populated driver data.
>
> Signed-off-by: Mingyou Chen <[email protected]>
> ---
> drivers/platform/x86/bitland-mifs-wmi.c | 336 ++++++++++++++++++++++--
> 1 file changed, 318 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
> index 17792d8b7c29..1eb9f92740e0 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>
> @@ -71,6 +72,11 @@ enum bitland_system_ac_mode {
> WMI_SYSTEM_AC_CIRCULARHOLE = 2,
> };
>
> +enum bitland_kbd_type {
> + WMI_KBD_TYPE_WHITE = 0,
> + WMI_KBD_TYPE_RGB = 1,
> +};
> +
> enum bitland_mifs_power_profile {
> WMI_PP_BALANCED = 0,
> WMI_PP_PERFORMANCE = 1,
> @@ -97,7 +103,15 @@ static const struct bitland_profile_mode_map bitland_mode_map = {
> .full_speed = WMI_PP_FULL_SPEED,
> };
>
> +static const struct bitland_profile_mode_map redmi_mode_map = {
> + .balanced = 1,
> + .performance = 0,
> + .quiet = 2,
> + .full_speed = 4,
> +};
> +
> static int bitland_pp_check_capability(struct bitland_mifs_wmi_data *data);
> +static int redmi_pp_check_capability(struct bitland_mifs_wmi_data *data);
>
> /*
> * Machine-specific operations. The MIFS WMI interface is shared by
> @@ -109,6 +123,8 @@ struct bitland_mifs_ops {
> const struct bitland_profile_mode_map *mode_map;
> int (*check_performance_capability)(struct bitland_mifs_wmi_data *data);
> bool has_full_speed;
> + bool has_cpu_power;
> + bool quirk_refresh_rate_toggle;
> };
>
> static const struct bitland_mifs_ops bitland_ops = {
> @@ -118,6 +134,54 @@ static const struct bitland_mifs_ops bitland_ops = {
> .has_full_speed = true,
> };
>
> +static const struct bitland_mifs_ops redmi_book_ops = {
> + .name = "Redmi Book",
> + .mode_map = &redmi_mode_map,
> + .check_performance_capability = redmi_pp_check_capability,
> + .has_cpu_power = true,
> + .quirk_refresh_rate_toggle = true,
> +};
> +
> +static const struct bitland_mifs_ops redmi_g_ops = {
> + .name = "Redmi G",
> + .mode_map = &redmi_mode_map,
> + .check_performance_capability = redmi_pp_check_capability,
> + .has_full_speed = true,
> + .has_cpu_power = true,
> + .quirk_refresh_rate_toggle = true,
> +};
> +
> +static const struct dmi_system_id bitland_mifs_dmi_table[] = {
> + {
> + /* Redmi G */
> + .matches = {
> + DMI_MATCH(DMI_BOARD_NAME, "TM2135"),
> + },
> + .driver_data = (void *)&redmi_g_ops,
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_NAME, "TM2137"),
> + },
> + .driver_data = (void *)&redmi_g_ops,
> + },
> + {
> + /* Redmi Book series */
> + .matches = {
> + DMI_MATCH(DMI_SYS_VENDOR, "Redmi"),
> + },
> + .driver_data = (void *)&redmi_book_ops,
> + },
> + {
> + /* Xiaomi Book series */
> + .matches = {
> + DMI_MATCH(DMI_SYS_VENDOR, "TIMI"),
> + },
> + .driver_data = (void *)&redmi_book_ops,
> + },
> + {}
> +};
> +
> enum bitland_mifs_event_id {
> WMI_EVENT_RESERVED_1 = 1,
> WMI_EVENT_RESERVED_2 = 2,
> @@ -203,6 +267,8 @@ struct bitland_mifs_wmi_data {
> struct input_dev *input_dev;
> struct device *hwmon_dev;
> struct device *pp_dev;
> + enum bitland_wmi_device_type dev_type;
> + u8 kbd_type;
> const struct bitland_mifs_ops *ops;
> enum platform_profile_option saved_profile;
> };
> @@ -255,8 +321,10 @@ static int laptop_profile_get(struct device *dev,
> else if (mode == map->balanced)
> *profile = PLATFORM_PROFILE_BALANCED;
> else if (mode == map->performance)
> - *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
> - else if (mode == map->full_speed)
> + *profile = data->ops->has_full_speed ?
> + PLATFORM_PROFILE_BALANCED_PERFORMANCE :
> + PLATFORM_PROFILE_PERFORMANCE;
> + else if (data->ops->has_full_speed && mode == map->full_speed)
> *profile = PLATFORM_PROFILE_PERFORMANCE;
> else
> return -EINVAL;
> @@ -273,10 +341,11 @@ static int bitland_pp_check_capability(struct bitland_mifs_wmi_data *data)
> struct bitland_mifs_output output;
> int ret;
>
> - /* Full-speed/performance mode requires DC power (not USB-C) */
> + /* The performance modes require AC power */
> if (!power_supply_is_system_supplied())
> return -EOPNOTSUPP;
>
> + /* Additionally require the barrel-jack power supply (not USB-C) */
> ret = bitland_mifs_wmi_call(data, &input, &output);
> if (ret)
> return ret;
> @@ -287,6 +356,15 @@ static int bitland_pp_check_capability(struct bitland_mifs_wmi_data *data)
> return 0;
> }
>
> +static int redmi_pp_check_capability(struct bitland_mifs_wmi_data *data)
> +{
> + /* The performance modes require AC power (any source) */
> + if (!power_supply_is_system_supplied())
> + return -EOPNOTSUPP;
> +
> + return 0;
> +}
> +
> static int laptop_profile_set(struct device *dev,
> enum platform_profile_option profile)
> {
> @@ -309,6 +387,8 @@ static int laptop_profile_set(struct device *dev,
> mode = map->balanced;
> break;
> case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
> + if (!data->ops->has_full_speed)
> + return -EOPNOTSUPP;
> ret = data->ops->check_performance_capability(data);
> if (ret)
> return ret;
> @@ -318,7 +398,7 @@ static int laptop_profile_set(struct device *dev,
> ret = data->ops->check_performance_capability(data);
> if (ret)
> return ret;
> - mode = map->full_speed;
> + mode = data->ops->has_full_speed ? map->full_speed : map->performance;
> break;
> default:
> return -EOPNOTSUPP;
> @@ -335,10 +415,10 @@ 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);
>
> if (data->ops->has_full_speed)
> - set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
> + set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices);
>
> return 0;
> }
> @@ -418,6 +498,13 @@ static int laptop_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
> default:
> return -EINVAL;
> }
> + case hwmon_power:
> + /* WMI_FN_CPU_POWER returns the CPU power draw in watts */
> + input.function = WMI_FN_CPU_POWER;
> + ret = bitland_mifs_wmi_call(data, &input, &res);
> + if (!ret)
> + *val = res.data[0] * MICROWATT_PER_WATT;
> + return ret;
> default:
> return -EINVAL;
> }
> @@ -444,6 +531,15 @@ static const struct hwmon_channel_info *laptop_hwmon_info[] = {
> NULL
> };
>
> +static const struct hwmon_channel_info *laptop_hwmon_info_power[] = {
> + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
> + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL,
> + HWMON_F_INPUT | HWMON_F_LABEL,
> + HWMON_F_INPUT | HWMON_F_LABEL),
> + HWMON_CHANNEL_INFO(power, HWMON_P_INPUT),
> + NULL
> +};
> +
> static const struct hwmon_ops laptop_hwmon_ops = {
> .visible = 0444,
> .read = laptop_hwmon_read,
> @@ -455,6 +551,11 @@ static const struct hwmon_chip_info laptop_chip_info = {
> .info = laptop_hwmon_info,
> };
>
> +static const struct hwmon_chip_info laptop_chip_info_power = {
> + .ops = &laptop_hwmon_ops,
> + .info = laptop_hwmon_info_power,
> +};
> +
> static int laptop_kbd_led_set(struct led_classdev *led_cdev,
> enum led_brightness value)
> {
> @@ -498,6 +599,96 @@ static const char *const gpu_mode_strings[] = {
> "uma",
> };
>
> +static ssize_t fn_lock_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
> + struct bitland_mifs_input input = {
> + .reserved1 = 0,
> + .operation = WMI_METHOD_GET,
> + .reserved2 = 0,
> + .function = WMI_FN_FN_LOCK,
> + };
> + struct bitland_mifs_output res;
> + int ret;
> +
> + ret = bitland_mifs_wmi_call(data, &input, &res);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%u\n", res.data[0]);
> +}
> +
> +static ssize_t fn_lock_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
> + struct bitland_mifs_input input = {
> + .reserved1 = 0,
> + .operation = WMI_METHOD_SET,
> + .reserved2 = 0,
> + .function = WMI_FN_FN_LOCK,
> + };
> + bool val;
> + int ret;
> +
> + if (kstrtobool(buf, &val))
> + return -EINVAL;
> +
> + input.payload[0] = val;
> +
> + ret = bitland_mifs_wmi_call(data, &input, NULL);
> + if (ret)
> + return ret;
> +
> + return count;
> +}
> +
> +static ssize_t touchpad_lock_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
> + struct bitland_mifs_input input = {
> + .reserved1 = 0,
> + .operation = WMI_METHOD_GET,
> + .reserved2 = 0,
> + .function = WMI_FN_TP_LOCK,
> + };
> + struct bitland_mifs_output res;
> + int ret;
> +
> + ret = bitland_mifs_wmi_call(data, &input, &res);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%u\n", res.data[0]);
> +}
> +
> +static ssize_t touchpad_lock_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
> + struct bitland_mifs_input input = {
> + .reserved1 = 0,
> + .operation = WMI_METHOD_SET,
> + .reserved2 = 0,
> + .function = WMI_FN_TP_LOCK,
> + };
> + bool val;
> + int ret;
> +
> + if (kstrtobool(buf, &val))
> + return -EINVAL;
> +
> + input.payload[0] = val;
> +
> + ret = bitland_mifs_wmi_call(data, &input, NULL);
> + if (ret)
> + return ret;
> +
> + return count;
> +}
> +
> /* GPU Mode: 0:Hybrid, 1:Discrete, 2:UMA */
> static ssize_t gpu_mode_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> @@ -637,17 +828,46 @@ static ssize_t fan_boost_store(struct device *dev,
> return count;
> }
>
> -static const DEVICE_ATTR_RW(gpu_mode);
> -static const DEVICE_ATTR_RW(kb_mode);
> -static const DEVICE_ATTR_WO(fan_boost);
> +static DEVICE_ATTR_RW(gpu_mode);
> +static DEVICE_ATTR_RW(kb_mode);
> +static DEVICE_ATTR_WO(fan_boost);
> +static DEVICE_ATTR_RW(fn_lock);
> +static DEVICE_ATTR_RW(touchpad_lock);
>
> -static const struct attribute *const laptop_attrs[] = {
> +static struct attribute *laptop_attrs[] = {
> &dev_attr_gpu_mode.attr,
> &dev_attr_kb_mode.attr,
> &dev_attr_fan_boost.attr,
> + &dev_attr_fn_lock.attr,
> + &dev_attr_touchpad_lock.attr,
> NULL,
> };
> -ATTRIBUTE_GROUPS(laptop);
> +
> +static umode_t laptop_attr_is_visible(struct kobject *kobj,
> + struct attribute *attr, int idx)
> +{
> + struct device *dev = kobj_to_dev(kobj);
> + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
> +
> + /* The sysfs attributes are only supported on the control device */
> + if (data->dev_type != BITLAND_WMI_CONTROL)
> + return 0;
> +
> + /*
> + * White-only backlit keyboards (e.g. Redmi Book series) do not
> + * support the RGB backlight modes.
> + */
> + if (attr == &dev_attr_kb_mode.attr &&
> + data->kbd_type == WMI_KBD_TYPE_WHITE)
> + return 0;
> +
> + return attr->mode;
> +}
> +
> +static const struct attribute_group laptop_group = {
> + .attrs = laptop_attrs,
> + .is_visible = laptop_attr_is_visible,
> +};
>
> static const struct key_entry bitland_mifs_wmi_keymap[] = {
> { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_OPEN_APP, 1, 0), { KEY_PROG1 } },
> @@ -699,6 +919,34 @@ static const struct key_entry bitland_mifs_wmi_keymap[] = {
> { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_FNLOCK_STATE, 0, 0), {} },
> { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_FNLOCK_STATE, 1, 0), {} },
>
> + /* Airplane mode toggle (Redmi) */
> + { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_AIRPLANE_MODE, 0, 0), { KEY_RFKILL } },
> + { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_AIRPLANE_MODE, 1, 0), { KEY_RFKILL } },
> +
> + /*
> + * Touchpad state change (Redmi Fn+F7). The EC performs the actual
> + * toggle itself; userspace can control the state via the
> + * touchpad_lock sysfs attribute.
> + */
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_TOUCHPAD_STATE, 0, 0), {} },
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_TOUCHPAD_STATE, 1, 0), {} },
> +
> + /* Keyboard backlight mode change */
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_KBD_MODE, 0, 0), {} },
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_KBD_MODE, 1, 0), {} },
> +
> + /* Lock-state indicator events */
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_CAPSLOCK_STATE, 0, 0), {} },
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_CAPSLOCK_STATE, 1, 0), {} },
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_NUMLOCK_STATE, 0, 0), {} },
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_NUMLOCK_STATE, 1, 0), {} },
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_SCROLLLOCK_STATE, 0, 0), {} },
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_SCROLLLOCK_STATE, 1, 0), {} },
> +
> + /* Win key lock (Redmi gaming mode) */
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_WIN_KEY_LOCK, 0, 0), {} },
> + { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_WIN_KEY_LOCK, 1, 0), {} },
> +
> /* Fn+`/1/2/3/4 */
> { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FN_F, 1, 0), { KEY_F13 } },
> { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FN_0, 1, 0), { KEY_F14 } },
> @@ -744,6 +992,36 @@ static int bitland_notifier_callback(struct notifier_block *nb,
> return NOTIFY_OK;
> }
>
> +static int bitland_detect_kbd_type(struct bitland_mifs_wmi_data *data)
> +{
> + struct bitland_mifs_input input = {
> + .reserved1 = 0,
> + .operation = WMI_METHOD_GET,
> + .reserved2 = 0,
> + .function = WMI_FN_KBD_TYPE,
> + };
> + struct bitland_mifs_output res;
> + int ret;
> +
> + ret = bitland_mifs_wmi_call(data, &input, &res);
> + if (ret)
> + return ret;
> +
> + data->kbd_type = res.data[0];
> + return 0;
> +}
> +
> +static void bitland_detect_ops(struct bitland_mifs_wmi_data *data)
> +{
> + const struct dmi_system_id *id;
> +
> + id = dmi_first_match(bitland_mifs_dmi_table);
> + if (id)
> + data->ops = id->driver_data;
> +
> + dev_dbg(&data->wdev->dev, "Detected machine ops: %s\n", data->ops->name);
> +}
> +
> static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
> {
> struct bitland_mifs_wmi_data *drv_data;
> @@ -761,6 +1039,9 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
> return -ENOMEM;
>
> drv_data->wdev = wdev;
> + drv_data->dev_type = dev_type;
> + /* Default to RGB so the RGB attributes stay visible if detection fails */
> + drv_data->kbd_type = WMI_KBD_TYPE_RGB;
> drv_data->ops = &bitland_ops;
>
> ret = devm_mutex_init(&wdev->dev, &drv_data->lock);
> @@ -769,6 +1050,8 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
>
> dev_set_drvdata(&wdev->dev, drv_data);
>
> + bitland_detect_ops(drv_data);
> +
> if (dev_type == BITLAND_WMI_EVENT) {
> /* Register input device for hotkeys */
> drv_data->input_dev = devm_input_allocate_device(&wdev->dev);
> @@ -794,12 +1077,28 @@ 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);
>
> + /* Detect the keyboard type */
> + ret = bitland_detect_kbd_type(drv_data);
> + if (ret)
> + dev_dbg(&wdev->dev, "Failed to detect keyboard type, assuming RGB: %d\n", ret);
> +
> + ret = devm_device_add_group(&wdev->dev, &laptop_group);
> + if (ret)
> + return ret;
> +
> /* Register hwmon */
> - drv_data->hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev,
> - "bitland_mifs",
> - drv_data,
> - &laptop_chip_info,
> - NULL);
> + if (drv_data->ops->has_cpu_power)
> + drv_data->hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev,
> + "bitland_mifs",
> + drv_data,
> + &laptop_chip_info_power,
> + NULL);
> + else
> + drv_data->hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev,
> + "bitland_mifs",
> + drv_data,
> + &laptop_chip_info,
> + NULL);
> if (IS_ERR(drv_data->hwmon_dev))
> return PTR_ERR(drv_data->hwmon_dev);
>
> @@ -851,6 +1150,7 @@ static void bitland_mifs_wmi_report_key(struct wmi_device *wdev, u32 payload)
> static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
> const struct wmi_buffer *buffer)
> {
> + struct bitland_mifs_wmi_data *data = dev_get_drvdata(&wdev->dev);
> const struct bitland_mifs_event *event = buffer->data;
> struct bitland_fan_notify_data fan_data;
> u32 payload;
> @@ -885,7 +1185,8 @@ static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
> case WMI_EVENT_CPU_FAN_SPEED:
> case WMI_EVENT_GPU_FAN_SPEED:
> /* Redmi refresh rate toggle quirk */
> - if (event->event_id == WMI_EVENT_CPU_FAN_SPEED &&
> + if (data->ops->quirk_refresh_rate_toggle &&
> + event->event_id == WMI_EVENT_CPU_FAN_SPEED &&
> event->value_low == 0 && event->value_high == 0) {
> payload = BI_HOTKEY_CODE(WMI_EVENT_REFRESH_RATE, 0, 0);
> bitland_mifs_wmi_report_key(wdev, payload);
> @@ -923,7 +1224,6 @@ static struct wmi_driver bitland_mifs_wmi_driver = {
> .no_singleton = true,
> .driver = {
> .name = DRV_NAME,
> - .dev_groups = laptop_groups,
> .pm = pm_sleep_ptr(&bitland_mifs_wmi_pm_ops),
> },
> .id_table = bitland_mifs_wmi_id_table,
> --
> 2.55.0
>