Commit 446dd8ef authored by SungHwan Jung's avatar SungHwan Jung Committed by Hans de Goede

platform/x86: acer-wmi: add fan speed monitoring for Predator PHN16-71

Support CPU and GPU fan speed monitoring through WMI for Predator
PHN16-71.
Signed-off-by: default avatarSungHwan Jung <onenowy@gmail.com>
Link: https://lore.kernel.org/r/20231124094122.100707-3-onenowy@gmail.comReviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent c0ff2c39
...@@ -178,6 +178,7 @@ config ACER_WMI ...@@ -178,6 +178,7 @@ config ACER_WMI
depends on RFKILL || RFKILL = n depends on RFKILL || RFKILL = n
depends on ACPI_WMI depends on ACPI_WMI
depends on ACPI_VIDEO || ACPI_VIDEO = n depends on ACPI_VIDEO || ACPI_VIDEO = n
depends on HWMON
select INPUT_SPARSEKMAP select INPUT_SPARSEKMAP
select LEDS_CLASS select LEDS_CLASS
select NEW_LEDS select NEW_LEDS
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/sparse-keymap.h> #include <linux/input/sparse-keymap.h>
#include <acpi/video.h> #include <acpi/video.h>
#include <linux/hwmon.h>
#include <linux/bitfield.h>
MODULE_AUTHOR("Carlos Corbacho"); MODULE_AUTHOR("Carlos Corbacho");
MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
...@@ -69,6 +71,8 @@ MODULE_LICENSE("GPL"); ...@@ -69,6 +71,8 @@ MODULE_LICENSE("GPL");
#define ACER_PREDATOR_V4_THERMAL_PROFILE_EC_OFFSET 0x54 #define ACER_PREDATOR_V4_THERMAL_PROFILE_EC_OFFSET 0x54
#define ACER_PREDATOR_V4_FAN_SPEED_READ_BIT_MASK GENMASK(20, 8)
/* /*
* Acer ACPI method GUIDs * Acer ACPI method GUIDs
*/ */
...@@ -96,6 +100,8 @@ enum acer_wmi_event_ids { ...@@ -96,6 +100,8 @@ enum acer_wmi_event_ids {
enum acer_wmi_predator_v4_sys_info_command { enum acer_wmi_predator_v4_sys_info_command {
ACER_WMID_CMD_GET_PREDATOR_V4_BAT_STATUS = 0x02, ACER_WMID_CMD_GET_PREDATOR_V4_BAT_STATUS = 0x02,
ACER_WMID_CMD_GET_PREDATOR_V4_CPU_FAN_SPEED = 0x0201,
ACER_WMID_CMD_GET_PREDATOR_V4_GPU_FAN_SPEED = 0x0601,
}; };
static const struct key_entry acer_wmi_keymap[] __initconst = { static const struct key_entry acer_wmi_keymap[] __initconst = {
...@@ -241,6 +247,7 @@ struct hotkey_function_type_aa { ...@@ -241,6 +247,7 @@ struct hotkey_function_type_aa {
#define ACER_CAP_TURBO_LED BIT(8) #define ACER_CAP_TURBO_LED BIT(8)
#define ACER_CAP_TURBO_FAN BIT(9) #define ACER_CAP_TURBO_FAN BIT(9)
#define ACER_CAP_PLATFORM_PROFILE BIT(10) #define ACER_CAP_PLATFORM_PROFILE BIT(10)
#define ACER_CAP_FAN_SPEED_READ BIT(11)
/* /*
* Interface type flags * Interface type flags
...@@ -352,7 +359,8 @@ static void __init set_quirks(void) ...@@ -352,7 +359,8 @@ static void __init set_quirks(void)
| ACER_CAP_TURBO_FAN; | ACER_CAP_TURBO_FAN;
if (quirks->predator_v4) if (quirks->predator_v4)
interface->capability |= ACER_CAP_PLATFORM_PROFILE; interface->capability |= ACER_CAP_PLATFORM_PROFILE |
ACER_CAP_FAN_SPEED_READ;
} }
static int __init dmi_matched(const struct dmi_system_id *dmi) static int __init dmi_matched(const struct dmi_system_id *dmi)
...@@ -1718,6 +1726,26 @@ static int acer_gsensor_event(void) ...@@ -1718,6 +1726,26 @@ static int acer_gsensor_event(void)
return 0; return 0;
} }
static int acer_get_fan_speed(int fan)
{
if (quirks->predator_v4) {
acpi_status status;
u64 fanspeed;
status = WMI_gaming_execute_u64(
ACER_WMID_GET_GAMING_SYS_INFO_METHODID,
fan == 0 ? ACER_WMID_CMD_GET_PREDATOR_V4_CPU_FAN_SPEED :
ACER_WMID_CMD_GET_PREDATOR_V4_GPU_FAN_SPEED,
&fanspeed);
if (ACPI_FAILURE(status))
return -EIO;
return FIELD_GET(ACER_PREDATOR_V4_FAN_SPEED_READ_BIT_MASK, fanspeed);
}
return -EOPNOTSUPP;
}
/* /*
* Predator series turbo button * Predator series turbo button
*/ */
...@@ -2472,6 +2500,8 @@ static u32 get_wmid_devices(void) ...@@ -2472,6 +2500,8 @@ static u32 get_wmid_devices(void)
return devices; return devices;
} }
static int acer_wmi_hwmon_init(void);
/* /*
* Platform device * Platform device
*/ */
...@@ -2501,8 +2531,17 @@ static int acer_platform_probe(struct platform_device *device) ...@@ -2501,8 +2531,17 @@ static int acer_platform_probe(struct platform_device *device)
goto error_platform_profile; goto error_platform_profile;
} }
if (has_cap(ACER_CAP_FAN_SPEED_READ)) {
err = acer_wmi_hwmon_init();
if (err)
goto error_hwmon;
}
return 0; return 0;
error_hwmon:
if (platform_profile_support)
platform_profile_remove();
error_platform_profile: error_platform_profile:
acer_rfkill_exit(); acer_rfkill_exit();
error_rfkill: error_rfkill:
...@@ -2612,6 +2651,73 @@ static void __init create_debugfs(void) ...@@ -2612,6 +2651,73 @@ static void __init create_debugfs(void)
&interface->debug.wmid_devices); &interface->debug.wmid_devices);
} }
static umode_t acer_wmi_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type, u32 attr,
int channel)
{
switch (type) {
case hwmon_fan:
if (acer_get_fan_speed(channel) >= 0)
return 0444;
break;
default:
return 0;
}
return 0;
}
static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
int ret;
switch (type) {
case hwmon_fan:
ret = acer_get_fan_speed(channel);
if (ret < 0)
return ret;
*val = ret;
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static const struct hwmon_channel_info *const acer_wmi_hwmon_info[] = {
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT), NULL
};
static const struct hwmon_ops acer_wmi_hwmon_ops = {
.read = acer_wmi_hwmon_read,
.is_visible = acer_wmi_hwmon_is_visible,
};
static const struct hwmon_chip_info acer_wmi_hwmon_chip_info = {
.ops = &acer_wmi_hwmon_ops,
.info = acer_wmi_hwmon_info,
};
static int acer_wmi_hwmon_init(void)
{
struct device *dev = &acer_platform_device->dev;
struct device *hwmon;
hwmon = devm_hwmon_device_register_with_info(dev, "acer",
&acer_platform_driver,
&acer_wmi_hwmon_chip_info,
NULL);
if (IS_ERR(hwmon)) {
dev_err(dev, "Could not register acer hwmon device\n");
return PTR_ERR(hwmon);
}
return 0;
}
static int __init acer_wmi_init(void) static int __init acer_wmi_init(void)
{ {
int err; int err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment