MSI's version of platform profile in Windows is called shift mode. Introduce it here, and add a profile handler to it. It has 5 modes: sport, comfort, green, eco, and user. Confusingly, for the Claw, MSI only uses sport, green, and eco, where they correspond to performance, balanced, and low-power. Therefore, comfort is mapped to balanced-performance, and user to custom. Signed-off-by: Antheas Kapenekakis <lkml@xxxxxxxxxxx> --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/msi-wmi-platform.c | 117 ++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index bee98251b8f0b..57a48910c8fd4 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -746,6 +746,7 @@ config MSI_WMI_PLATFORM tristate "MSI WMI Platform features" depends on ACPI_WMI depends on HWMON + select ACPI_PLATFORM_PROFILE help Say Y here if you want to have support for WMI-based platform features like fan sensor access on MSI machines. diff --git a/drivers/platform/x86/msi-wmi-platform.c b/drivers/platform/x86/msi-wmi-platform.c index 9ac3c6f1b3f1d..c0b577c95c079 100644 --- a/drivers/platform/x86/msi-wmi-platform.c +++ b/drivers/platform/x86/msi-wmi-platform.c @@ -17,6 +17,7 @@ #include <linux/dmi.h> #include <linux/errno.h> #include <linux/fixp-arith.h> +#include <linux/platform_profile.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/kernel.h> @@ -63,6 +64,16 @@ #define MSI_PLATFORM_AP_FAN_FLAGS_OFFSET 1 #define MSI_PLATFORM_AP_ENABLE_FAN_TABLES BIT(7) +/* Get_Data() and Set_Data() Shift Mode Register */ +#define MSI_PLATFORM_SHIFT_ADDR 0xd2 +#define MSI_PLATFORM_SHIFT_DISABLE BIT(7) +#define MSI_PLATFORM_SHIFT_ENABLE (BIT(7) | BIT(6)) +#define MSI_PLATFORM_SHIFT_SPORT (MSI_PLATFORM_SHIFT_ENABLE + 4) +#define MSI_PLATFORM_SHIFT_COMFORT (MSI_PLATFORM_SHIFT_ENABLE + 0) +#define MSI_PLATFORM_SHIFT_GREEN (MSI_PLATFORM_SHIFT_ENABLE + 1) +#define MSI_PLATFORM_SHIFT_ECO (MSI_PLATFORM_SHIFT_ENABLE + 2) +#define MSI_PLATFORM_SHIFT_USER (MSI_PLATFORM_SHIFT_ENABLE + 3) + static bool force; module_param_unsafe(force, bool, 0); MODULE_PARM_DESC(force, "Force loading without checking for supported WMI interface versions"); @@ -100,12 +111,14 @@ enum msi_wmi_platform_method { }; struct msi_wmi_platform_quirk { + bool shift_mode; /* Shift mode is supported */ }; struct msi_wmi_platform_data { struct wmi_device *wdev; struct msi_wmi_platform_quirk *quirks; struct mutex wmi_lock; /* Necessary when calling WMI methods */ + struct device *ppdev; }; struct msi_wmi_platform_debugfs_data { @@ -150,8 +163,10 @@ static const char * const msi_wmi_platform_debugfs_names[] = { static struct msi_wmi_platform_quirk quirk_default = {}; static struct msi_wmi_platform_quirk quirk_gen1 = { + .shift_mode = true }; static struct msi_wmi_platform_quirk quirk_gen2 = { + .shift_mode = true }; static const struct dmi_system_id msi_quirks[] = { @@ -561,6 +576,90 @@ static const struct hwmon_chip_info msi_wmi_platform_chip_info = { .info = msi_wmi_platform_info, }; +static int msi_wmi_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); + return 0; +} + +static int msi_wmi_platform_profile_get(struct device *dev, + enum platform_profile_option *profile) +{ + struct msi_wmi_platform_data *data = dev_get_drvdata(dev); + int ret; + + u8 buffer[32] = { }; + + buffer[0] = MSI_PLATFORM_SHIFT_ADDR; + + ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_DATA, buffer, sizeof(buffer)); + if (ret < 0) + return ret; + + if (buffer[0] != 1) + return -EINVAL; + + switch (buffer[1]) { + case MSI_PLATFORM_SHIFT_SPORT: + *profile = PLATFORM_PROFILE_PERFORMANCE; + return 0; + case MSI_PLATFORM_SHIFT_COMFORT: + *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE; + return 0; + case MSI_PLATFORM_SHIFT_GREEN: + *profile = PLATFORM_PROFILE_BALANCED; + return 0; + case MSI_PLATFORM_SHIFT_ECO: + *profile = PLATFORM_PROFILE_LOW_POWER; + return 0; + case MSI_PLATFORM_SHIFT_USER: + *profile = PLATFORM_PROFILE_CUSTOM; + return 0; + default: + return -EINVAL; + } +} + +static int msi_wmi_platform_profile_set(struct device *dev, + enum platform_profile_option profile) +{ + struct msi_wmi_platform_data *data = dev_get_drvdata(dev); + u8 buffer[32] = { }; + + buffer[0] = MSI_PLATFORM_SHIFT_ADDR; + + switch (profile) { + case PLATFORM_PROFILE_PERFORMANCE: + buffer[1] = MSI_PLATFORM_SHIFT_SPORT; + break; + case PLATFORM_PROFILE_BALANCED_PERFORMANCE: + buffer[1] = MSI_PLATFORM_SHIFT_COMFORT; + break; + case PLATFORM_PROFILE_BALANCED: + buffer[1] = MSI_PLATFORM_SHIFT_GREEN; + break; + case PLATFORM_PROFILE_LOW_POWER: + buffer[1] = MSI_PLATFORM_SHIFT_ECO; + break; + case PLATFORM_PROFILE_CUSTOM: + buffer[1] = MSI_PLATFORM_SHIFT_USER; + break; + default: + return -EINVAL; + } + + return msi_wmi_platform_query(data, MSI_PLATFORM_SET_DATA, buffer, sizeof(buffer)); +} + +static const struct platform_profile_ops msi_wmi_platform_profile_ops = { + .probe = msi_wmi_platform_profile_probe, + .profile_get = msi_wmi_platform_profile_get, + .profile_set = msi_wmi_platform_profile_set, +}; + static ssize_t msi_wmi_platform_debugfs_write(struct file *fp, const char __user *input, size_t length, loff_t *offset) { @@ -742,6 +841,22 @@ static int msi_wmi_platform_init(struct msi_wmi_platform_data *data) return 0; } +static int msi_wmi_platform_profile_setup(struct msi_wmi_platform_data *data) +{ + int err; + + if (!data->quirks->shift_mode) + return 0; + + data->ppdev = devm_platform_profile_register( + &data->wdev->dev, "msi-wmi-platform", data, + &msi_wmi_platform_profile_ops); + if (err) + return err; + + return PTR_ERR_OR_ZERO(data->ppdev); +} + static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context) { struct msi_wmi_platform_data *data; @@ -775,6 +890,8 @@ static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context) msi_wmi_platform_debugfs_init(data); + msi_wmi_platform_profile_setup(data); + return msi_wmi_platform_hwmon_init(data); } -- 2.49.0