|
17 | 17 | #include <linux/dmi.h> |
18 | 18 | #include <linux/errno.h> |
19 | 19 | #include <linux/fixp-arith.h> |
| 20 | +#include <linux/platform_profile.h> |
20 | 21 | #include <linux/hwmon.h> |
21 | 22 | #include <linux/hwmon-sysfs.h> |
22 | 23 | #include <linux/kernel.h> |
|
63 | 64 | #define MSI_PLATFORM_AP_FAN_FLAGS_OFFSET 1 |
64 | 65 | #define MSI_PLATFORM_AP_ENABLE_FAN_TABLES BIT(7) |
65 | 66 |
|
| 67 | +/* Get_Data() and Set_Data() Shift Mode Register */ |
| 68 | +#define MSI_PLATFORM_SHIFT_ADDR 0xd2 |
| 69 | +#define MSI_PLATFORM_SHIFT_DISABLE BIT(7) |
| 70 | +#define MSI_PLATFORM_SHIFT_ENABLE (BIT(7) | BIT(6)) |
| 71 | +#define MSI_PLATFORM_SHIFT_SPORT (MSI_PLATFORM_SHIFT_ENABLE + 4) |
| 72 | +#define MSI_PLATFORM_SHIFT_COMFORT (MSI_PLATFORM_SHIFT_ENABLE + 0) |
| 73 | +#define MSI_PLATFORM_SHIFT_GREEN (MSI_PLATFORM_SHIFT_ENABLE + 1) |
| 74 | +#define MSI_PLATFORM_SHIFT_ECO (MSI_PLATFORM_SHIFT_ENABLE + 2) |
| 75 | +#define MSI_PLATFORM_SHIFT_USER (MSI_PLATFORM_SHIFT_ENABLE + 3) |
| 76 | + |
66 | 77 | static bool force; |
67 | 78 | module_param_unsafe(force, bool, 0); |
68 | 79 | MODULE_PARM_DESC(force, "Force loading without checking for supported WMI interface versions"); |
@@ -100,12 +111,14 @@ enum msi_wmi_platform_method { |
100 | 111 | }; |
101 | 112 |
|
102 | 113 | struct msi_wmi_platform_quirk { |
| 114 | + bool shift_mode; /* Shift mode is supported */ |
103 | 115 | }; |
104 | 116 |
|
105 | 117 | struct msi_wmi_platform_data { |
106 | 118 | struct wmi_device *wdev; |
107 | 119 | struct msi_wmi_platform_quirk *quirks; |
108 | 120 | struct mutex wmi_lock; /* Necessary when calling WMI methods */ |
| 121 | + struct device *ppdev; |
109 | 122 | }; |
110 | 123 |
|
111 | 124 | struct msi_wmi_platform_debugfs_data { |
@@ -150,8 +163,10 @@ static const char * const msi_wmi_platform_debugfs_names[] = { |
150 | 163 |
|
151 | 164 | static struct msi_wmi_platform_quirk quirk_default = {}; |
152 | 165 | static struct msi_wmi_platform_quirk quirk_gen1 = { |
| 166 | + .shift_mode = true |
153 | 167 | }; |
154 | 168 | static struct msi_wmi_platform_quirk quirk_gen2 = { |
| 169 | + .shift_mode = true |
155 | 170 | }; |
156 | 171 |
|
157 | 172 | static const struct dmi_system_id msi_quirks[] = { |
@@ -561,6 +576,90 @@ static const struct hwmon_chip_info msi_wmi_platform_chip_info = { |
561 | 576 | .info = msi_wmi_platform_info, |
562 | 577 | }; |
563 | 578 |
|
| 579 | +static int msi_wmi_platform_profile_probe(void *drvdata, unsigned long *choices) |
| 580 | +{ |
| 581 | + set_bit(PLATFORM_PROFILE_LOW_POWER, choices); |
| 582 | + set_bit(PLATFORM_PROFILE_BALANCED, choices); |
| 583 | + set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices); |
| 584 | + set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); |
| 585 | + return 0; |
| 586 | +} |
| 587 | + |
| 588 | +static int msi_wmi_platform_profile_get(struct device *dev, |
| 589 | + enum platform_profile_option *profile) |
| 590 | +{ |
| 591 | + struct msi_wmi_platform_data *data = dev_get_drvdata(dev); |
| 592 | + int ret; |
| 593 | + |
| 594 | + u8 buffer[32] = { }; |
| 595 | + |
| 596 | + buffer[0] = MSI_PLATFORM_SHIFT_ADDR; |
| 597 | + |
| 598 | + ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_DATA, buffer, sizeof(buffer)); |
| 599 | + if (ret < 0) |
| 600 | + return ret; |
| 601 | + |
| 602 | + if (buffer[0] != 1) |
| 603 | + return -EINVAL; |
| 604 | + |
| 605 | + switch (buffer[1]) { |
| 606 | + case MSI_PLATFORM_SHIFT_SPORT: |
| 607 | + *profile = PLATFORM_PROFILE_PERFORMANCE; |
| 608 | + return 0; |
| 609 | + case MSI_PLATFORM_SHIFT_COMFORT: |
| 610 | + *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE; |
| 611 | + return 0; |
| 612 | + case MSI_PLATFORM_SHIFT_GREEN: |
| 613 | + *profile = PLATFORM_PROFILE_BALANCED; |
| 614 | + return 0; |
| 615 | + case MSI_PLATFORM_SHIFT_ECO: |
| 616 | + *profile = PLATFORM_PROFILE_LOW_POWER; |
| 617 | + return 0; |
| 618 | + case MSI_PLATFORM_SHIFT_USER: |
| 619 | + *profile = PLATFORM_PROFILE_CUSTOM; |
| 620 | + return 0; |
| 621 | + default: |
| 622 | + return -EINVAL; |
| 623 | + } |
| 624 | +} |
| 625 | + |
| 626 | +static int msi_wmi_platform_profile_set(struct device *dev, |
| 627 | + enum platform_profile_option profile) |
| 628 | +{ |
| 629 | + struct msi_wmi_platform_data *data = dev_get_drvdata(dev); |
| 630 | + u8 buffer[32] = { }; |
| 631 | + |
| 632 | + buffer[0] = MSI_PLATFORM_SHIFT_ADDR; |
| 633 | + |
| 634 | + switch (profile) { |
| 635 | + case PLATFORM_PROFILE_PERFORMANCE: |
| 636 | + buffer[1] = MSI_PLATFORM_SHIFT_SPORT; |
| 637 | + break; |
| 638 | + case PLATFORM_PROFILE_BALANCED_PERFORMANCE: |
| 639 | + buffer[1] = MSI_PLATFORM_SHIFT_COMFORT; |
| 640 | + break; |
| 641 | + case PLATFORM_PROFILE_BALANCED: |
| 642 | + buffer[1] = MSI_PLATFORM_SHIFT_GREEN; |
| 643 | + break; |
| 644 | + case PLATFORM_PROFILE_LOW_POWER: |
| 645 | + buffer[1] = MSI_PLATFORM_SHIFT_ECO; |
| 646 | + break; |
| 647 | + case PLATFORM_PROFILE_CUSTOM: |
| 648 | + buffer[1] = MSI_PLATFORM_SHIFT_USER; |
| 649 | + break; |
| 650 | + default: |
| 651 | + return -EINVAL; |
| 652 | + } |
| 653 | + |
| 654 | + return msi_wmi_platform_query(data, MSI_PLATFORM_SET_DATA, buffer, sizeof(buffer)); |
| 655 | +} |
| 656 | + |
| 657 | +static const struct platform_profile_ops msi_wmi_platform_profile_ops = { |
| 658 | + .probe = msi_wmi_platform_profile_probe, |
| 659 | + .profile_get = msi_wmi_platform_profile_get, |
| 660 | + .profile_set = msi_wmi_platform_profile_set, |
| 661 | +}; |
| 662 | + |
564 | 663 | static ssize_t msi_wmi_platform_debugfs_write(struct file *fp, const char __user *input, |
565 | 664 | size_t length, loff_t *offset) |
566 | 665 | { |
@@ -742,6 +841,22 @@ static int msi_wmi_platform_init(struct msi_wmi_platform_data *data) |
742 | 841 | return 0; |
743 | 842 | } |
744 | 843 |
|
| 844 | +static int msi_wmi_platform_profile_setup(struct msi_wmi_platform_data *data) |
| 845 | +{ |
| 846 | + int err; |
| 847 | + |
| 848 | + if (!data->quirks->shift_mode) |
| 849 | + return 0; |
| 850 | + |
| 851 | + data->ppdev = devm_platform_profile_register( |
| 852 | + &data->wdev->dev, "msi-wmi-platform", data, |
| 853 | + &msi_wmi_platform_profile_ops); |
| 854 | + if (err) |
| 855 | + return err; |
| 856 | + |
| 857 | + return PTR_ERR_OR_ZERO(data->ppdev); |
| 858 | +} |
| 859 | + |
745 | 860 | static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context) |
746 | 861 | { |
747 | 862 | struct msi_wmi_platform_data *data; |
@@ -775,6 +890,8 @@ static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context) |
775 | 890 |
|
776 | 891 | msi_wmi_platform_debugfs_init(data); |
777 | 892 |
|
| 893 | + msi_wmi_platform_profile_setup(data); |
| 894 | + |
778 | 895 | return msi_wmi_platform_hwmon_init(data); |
779 | 896 | } |
780 | 897 |
|
|
0 commit comments