// SPDX-License-Identifier: GPL-2.0-or-later /* * Lenovo GameZone WMI interface driver. * * The GameZone WMI interface provides platform profile and fan curve settings * for devices that fall under the "Gaming Series" of Lenovo Legion devices. * * Copyright (C) 2025 Derek J. Clark <derekjohn.clark@gmail.com>
*/
/** * lwmi_gz_event_call() - Call method for lenovo-wmi-events driver notifier. * block call chain. * @nb: The notifier_block registered to lenovo-wmi-events driver. * @cmd: The event type. * @data: The data to be updated by the event. * * For LWMI_EVENT_THERMAL_MODE, set current_mode and notify platform_profile * of a change. * * Return: notifier_block status.
*/ staticint lwmi_gz_event_call(struct notifier_block *nb, unsignedlong cmd, void *data)
{ enum thermal_mode *mode = data; struct lwmi_gz_priv *priv;
/** * lwmi_gz_thermal_mode_supported() - Get the version of the WMI * interface to determine the support level. * @wdev: The Gamezone WMI device. * @supported: Pointer to return the support level with. * * Return: 0 on success, or an error code.
*/ staticint lwmi_gz_thermal_mode_supported(struct wmi_device *wdev, int *supported)
{ return lwmi_dev_evaluate_int(wdev, 0x0, LWMI_GZ_METHOD_ID_SMARTFAN_SUP,
NULL, 0, supported);
}
/** * lwmi_gz_thermal_mode_get() - Get the current thermal mode. * @wdev: The Gamezone interface WMI device. * @mode: Pointer to return the thermal mode with. * * Return: 0 on success, or an error code.
*/ staticint lwmi_gz_thermal_mode_get(struct wmi_device *wdev, enum thermal_mode *mode)
{ return lwmi_dev_evaluate_int(wdev, 0x0, LWMI_GZ_METHOD_ID_SMARTFAN_GET,
NULL, 0, mode);
}
/** * lwmi_gz_profile_get() - Get the current platform profile. * @dev: the Gamezone interface parent device. * @profile: Pointer to provide the current platform profile with. * * Call lwmi_gz_thermal_mode_get and convert the thermal mode into a platform * profile based on the support level of the interface. * * Return: 0 on success, or an error code.
*/ staticint lwmi_gz_profile_get(struct device *dev, enum platform_profile_option *profile)
{ struct lwmi_gz_priv *priv = dev_get_drvdata(dev); enum thermal_mode mode; int ret;
ret = lwmi_gz_thermal_mode_get(priv->wdev, &mode); if (ret) return ret;
switch (mode) { case LWMI_GZ_THERMAL_MODE_QUIET:
*profile = PLATFORM_PROFILE_LOW_POWER; break; case LWMI_GZ_THERMAL_MODE_BALANCED:
*profile = PLATFORM_PROFILE_BALANCED; break; case LWMI_GZ_THERMAL_MODE_PERFORMANCE: if (priv->extreme_supported) {
*profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE; break;
}
*profile = PLATFORM_PROFILE_PERFORMANCE; break; case LWMI_GZ_THERMAL_MODE_EXTREME:
*profile = PLATFORM_PROFILE_PERFORMANCE; break; case LWMI_GZ_THERMAL_MODE_CUSTOM:
*profile = PLATFORM_PROFILE_CUSTOM; break; default: return -EINVAL;
}
/** * lwmi_gz_profile_set() - Set the current platform profile. * @dev: The Gamezone interface parent device. * @profile: Pointer to the desired platform profile. * * Convert the given platform profile into a thermal mode based on the support * level of the interface, then call the WMI method to set the thermal mode. * * Return: 0 on success, or an error code.
*/ staticint lwmi_gz_profile_set(struct device *dev, enum platform_profile_option profile)
{ struct lwmi_gz_priv *priv = dev_get_drvdata(dev); struct wmi_method_args_32 args; enum thermal_mode mode; int ret;
switch (profile) { case PLATFORM_PROFILE_LOW_POWER:
mode = LWMI_GZ_THERMAL_MODE_QUIET; break; case PLATFORM_PROFILE_BALANCED:
mode = LWMI_GZ_THERMAL_MODE_BALANCED; break; case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
mode = LWMI_GZ_THERMAL_MODE_PERFORMANCE; break; case PLATFORM_PROFILE_PERFORMANCE: if (priv->extreme_supported) {
mode = LWMI_GZ_THERMAL_MODE_EXTREME; break;
}
mode = LWMI_GZ_THERMAL_MODE_PERFORMANCE; break; case PLATFORM_PROFILE_CUSTOM:
mode = LWMI_GZ_THERMAL_MODE_CUSTOM; break; default: return -EOPNOTSUPP;
}
args.arg0 = mode;
ret = lwmi_dev_evaluate_int(priv->wdev, 0x0,
LWMI_GZ_METHOD_ID_SMARTFAN_SET,
(u8 *)&args, sizeof(args), NULL); if (ret) return ret;
staticconststruct dmi_system_id fwbug_list[] = {
{
.ident = "Legion Go 8APU1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go 8APU1"),
},
.driver_data = &quirk_no_extreme_bug,
},
{
.ident = "Legion Go S 8APU1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go S 8APU1"),
},
.driver_data = &quirk_no_extreme_bug,
},
{
.ident = "Legion Go S 8ARP1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go S 8ARP1"),
},
.driver_data = &quirk_no_extreme_bug,
},
{},
};
/** * lwmi_gz_extreme_supported() - Evaluate if a device supports extreme thermal mode. * @profile_support_ver: Version of the WMI interface. * * Determine if the extreme thermal mode is supported by the hardware. * Anything version 5 or lower does not. For devices with a version 6 or * greater do a DMI check, as some devices report a version that supports * extreme mode but have an incomplete entry in the BIOS. To ensure this * cannot be set, quirk them to prevent assignment. * * Return: bool.
*/ staticbool lwmi_gz_extreme_supported(int profile_support_ver)
{ conststruct dmi_system_id *dmi_id; struct quirk_entry *quirks;
if (profile_support_ver < 6) returnfalse;
dmi_id = dmi_first_match(fwbug_list); if (!dmi_id) returntrue;
quirks = dmi_id->driver_data;
return quirks->extreme_supported;
}
/** * lwmi_gz_platform_profile_probe - Enable and set up the platform profile * device. * @drvdata: Driver data for the interface. * @choices: Container for enabled platform profiles. * * Determine if thermal mode is supported, and if so to what feature level. * Then enable all supported platform profiles. * * Return: 0 on success, or an error code.
*/ staticint lwmi_gz_platform_profile_probe(void *drvdata, unsignedlong *choices)
{ struct lwmi_gz_priv *priv = drvdata; int profile_support_ver; int ret;
ret = lwmi_gz_thermal_mode_supported(priv->wdev, &profile_support_ver); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.