summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/acer-wmi.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 85db9403cc14..694b45ed06a2 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -60,6 +60,11 @@ MODULE_LICENSE("GPL");
#define ACER_WMID_GET_THREEG_METHODID 10
#define ACER_WMID_SET_THREEG_METHODID 11
+#define ACER_WMID_SET_GAMING_LED_METHODID 2
+#define ACER_WMID_GET_GAMING_LED_METHODID 4
+#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14
+#define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22
+
/*
* Acer ACPI method GUIDs
*/
@@ -68,6 +73,7 @@ MODULE_LICENSE("GPL");
#define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
#define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A"
#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
+#define WMID_GUID4 "7A4DDFE7-5B5D-40B4-8595-4408E0CC7F56"
/*
* Acer ACPI event GUIDs
@@ -81,6 +87,7 @@ MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
enum acer_wmi_event_ids {
WMID_HOTKEY_EVENT = 0x1,
WMID_ACCEL_OR_KBD_DOCK_EVENT = 0x5,
+ WMID_GAMING_TURBO_KEY_EVENT = 0x7,
};
static const struct key_entry acer_wmi_keymap[] __initconst = {
@@ -215,6 +222,9 @@ struct hotkey_function_type_aa {
#define ACER_CAP_THREEG BIT(4)
#define ACER_CAP_SET_FUNCTION_MODE BIT(5)
#define ACER_CAP_KBD_DOCK BIT(6)
+#define ACER_CAP_TURBO_OC BIT(7)
+#define ACER_CAP_TURBO_LED BIT(8)
+#define ACER_CAP_TURBO_FAN BIT(9)
/*
* Interface type flags
@@ -301,6 +311,9 @@ struct quirk_entry {
u8 mailled;
s8 brightness;
u8 bluetooth;
+ u8 turbo;
+ u8 cpu_fans;
+ u8 gpu_fans;
};
static struct quirk_entry *quirks;
@@ -312,6 +325,10 @@ static void __init set_quirks(void)
if (quirks->brightness)
interface->capability |= ACER_CAP_BRIGHTNESS;
+
+ if (quirks->turbo)
+ interface->capability |= ACER_CAP_TURBO_OC | ACER_CAP_TURBO_LED
+ | ACER_CAP_TURBO_FAN;
}
static int __init dmi_matched(const struct dmi_system_id *dmi)
@@ -340,6 +357,12 @@ static struct quirk_entry quirk_acer_travelmate_2490 = {
.mailled = 1,
};
+static struct quirk_entry quirk_acer_predator_ph315_53 = {
+ .turbo = 1,
+ .cpu_fans = 1,
+ .gpu_fans = 1,
+};
+
/* This AMW0 laptop has no bluetooth */
static struct quirk_entry quirk_medion_md_98300 = {
.wireless = 1,
@@ -508,6 +531,15 @@ static const struct dmi_system_id acer_quirks[] __initconst = {
.driver_data = &quirk_acer_travelmate_2490,
},
{
+ .callback = dmi_matched,
+ .ident = "Acer Predator PH315-53",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH315-53"),
+ },
+ .driver_data = &quirk_acer_predator_ph315_53,
+ },
+ {
.callback = set_force_caps,
.ident = "Acer Aspire Switch 10E SW3-016",
.matches = {
@@ -1345,6 +1377,114 @@ static struct wmi_interface wmid_v2_interface = {
};
/*
+ * WMID Gaming interface
+ */
+
+static acpi_status
+WMI_gaming_execute_u64(u32 method_id, u64 in, u64 *out)
+{
+ struct acpi_buffer input = { (acpi_size) sizeof(u64), (void *)(&in) };
+ struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ u32 tmp = 0;
+ acpi_status status;
+
+ status = wmi_evaluate_method(WMID_GUID4, 0, method_id, &input, &result);
+
+ if (ACPI_FAILURE(status))
+ return status;
+ obj = (union acpi_object *) result.pointer;
+
+ if (obj) {
+ if (obj->type == ACPI_TYPE_BUFFER) {
+ if (obj->buffer.length == sizeof(u32))
+ tmp = *((u32 *) obj->buffer.pointer);
+ else if (obj->buffer.length == sizeof(u64))
+ tmp = *((u64 *) obj->buffer.pointer);
+ } else if (obj->type == ACPI_TYPE_INTEGER) {
+ tmp = (u64) obj->integer.value;
+ }
+ }
+
+ if (out)
+ *out = tmp;
+
+ kfree(result.pointer);
+
+ return status;
+}
+
+static acpi_status WMID_gaming_set_u64(u64 value, u32 cap)
+{
+ u32 method_id = 0;
+
+ if (!(interface->capability & cap))
+ return AE_BAD_PARAMETER;
+
+ switch (cap) {
+ case ACER_CAP_TURBO_LED:
+ method_id = ACER_WMID_SET_GAMING_LED_METHODID;
+ break;
+ case ACER_CAP_TURBO_FAN:
+ method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR;
+ break;
+ case ACER_CAP_TURBO_OC:
+ method_id = ACER_WMID_SET_GAMING_MISC_SETTING_METHODID;
+ break;
+ default:
+ return AE_BAD_PARAMETER;
+ }
+
+ return WMI_gaming_execute_u64(method_id, value, NULL);
+}
+
+static acpi_status WMID_gaming_get_u64(u64 *value, u32 cap)
+{
+ acpi_status status;
+ u64 result;
+ u64 input;
+ u32 method_id;
+
+ if (!(interface->capability & cap))
+ return AE_BAD_PARAMETER;
+
+ switch (cap) {
+ case ACER_CAP_TURBO_LED:
+ method_id = ACER_WMID_GET_GAMING_LED_METHODID;
+ input = 0x1;
+ break;
+ default:
+ return AE_BAD_PARAMETER;
+ }
+ status = WMI_gaming_execute_u64(method_id, input, &result);
+ if (ACPI_SUCCESS(status))
+ *value = (u64) result;
+
+ return status;
+}
+
+static void WMID_gaming_set_fan_mode(u8 fan_mode)
+{
+ /* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/
+ u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0;
+ int i;
+
+ if (quirks->cpu_fans > 0)
+ gpu_fan_config2 |= 1;
+ for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
+ gpu_fan_config2 |= 1 << (i + 1);
+ for (i = 0; i < quirks->gpu_fans; ++i)
+ gpu_fan_config2 |= 1 << (i + 3);
+ if (quirks->cpu_fans > 0)
+ gpu_fan_config1 |= fan_mode;
+ for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
+ gpu_fan_config1 |= fan_mode << (2 * i + 2);
+ for (i = 0; i < quirks->gpu_fans; ++i)
+ gpu_fan_config1 |= fan_mode << (2 * i + 6);
+ WMID_gaming_set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN);
+}
+
+/*
* Generic Device (interface-independent)
*/
@@ -1576,6 +1716,41 @@ static int acer_gsensor_event(void)
}
/*
+ * Predator series turbo button
+ */
+static int acer_toggle_turbo(void)
+{
+ u64 turbo_led_state;
+
+ /* Get current state from turbo button */
+ if (ACPI_FAILURE(WMID_gaming_get_u64(&turbo_led_state, ACER_CAP_TURBO_LED)))
+ return -1;
+
+ if (turbo_led_state) {
+ /* Turn off turbo led */
+ WMID_gaming_set_u64(0x1, ACER_CAP_TURBO_LED);
+
+ /* Set FAN mode to auto */
+ WMID_gaming_set_fan_mode(0x1);
+
+ /* Set OC to normal */
+ WMID_gaming_set_u64(0x5, ACER_CAP_TURBO_OC);
+ WMID_gaming_set_u64(0x7, ACER_CAP_TURBO_OC);
+ } else {
+ /* Turn on turbo led */
+ WMID_gaming_set_u64(0x10001, ACER_CAP_TURBO_LED);
+
+ /* Set FAN mode to turbo */
+ WMID_gaming_set_fan_mode(0x2);
+
+ /* Set OC to turbo mode */
+ WMID_gaming_set_u64(0x205, ACER_CAP_TURBO_OC);
+ WMID_gaming_set_u64(0x207, ACER_CAP_TURBO_OC);
+ }
+ return turbo_led_state;
+}
+
+/*
* Switch series keyboard dock status
*/
static int acer_kbd_dock_state_to_sw_tablet_mode(u8 kbd_dock_state)
@@ -1872,6 +2047,10 @@ static void acer_wmi_notify(u32 value, void *context)
acer_gsensor_event();
acer_kbd_dock_event(&return_value);
break;
+ case WMID_GAMING_TURBO_KEY_EVENT:
+ if (return_value.key_num == 0x4)
+ acer_toggle_turbo();
+ break;
default:
pr_warn("Unknown function number - %d - %d\n",
return_value.function, return_value.key_num);