mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 02:24:24 +02:00
platform/x86: hp-wmi: implement fan keep-alive
The firmware on some HP laptops automatically reverts the fan speed control to "Auto" mode after a 120 second timeout window. To ensure that the user-selected fan profile (Max/Manual) persists, implement a keep-alive mechanism that periodically refreshes the fan mode trigger before the timeout occurs. - Introduce a delayed workqueue to trigger the fan mode refresh every 90 seconds, ensuring the system maintains the correct fan mode setting. - Integrate the refresh mechanism into hp_wmi_apply_fan_settings() to start, update or cancel the keep-alive process based on the current fan mode. This ensures that the driver stays in sync with the hardware. Tested on: HP Omen 16-wf1xxx (board ID 8C78) Signed-off-by: Krishna Chomal <krishna.chomal108@gmail.com> Link: https://patch.msgid.link/20260113123738.222244-4-krishna.chomal108@gmail.com Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
parent
46be1453e6
commit
c203c59fb5
|
|
@ -34,6 +34,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
|
MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
|
||||||
MODULE_DESCRIPTION("HP laptop WMI driver");
|
MODULE_DESCRIPTION("HP laptop WMI driver");
|
||||||
|
|
@ -368,6 +369,7 @@ struct hp_wmi_hwmon_priv {
|
||||||
u8 gpu_delta;
|
u8 gpu_delta;
|
||||||
u8 mode;
|
u8 mode;
|
||||||
u8 pwm;
|
u8 pwm;
|
||||||
|
struct delayed_work keep_alive_dwork;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct victus_s_fan_table_header {
|
struct victus_s_fan_table_header {
|
||||||
|
|
@ -386,6 +388,12 @@ struct victus_s_fan_table {
|
||||||
struct victus_s_fan_table_entry entries[];
|
struct victus_s_fan_table_entry entries[];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 90s delay to prevent the firmware from resetting fan mode after fixed
|
||||||
|
* 120s timeout
|
||||||
|
*/
|
||||||
|
#define KEEP_ALIVE_DELAY_SECS 90
|
||||||
|
|
||||||
static inline u8 rpm_to_pwm(u8 rpm, struct hp_wmi_hwmon_priv *priv)
|
static inline u8 rpm_to_pwm(u8 rpm, struct hp_wmi_hwmon_priv *priv)
|
||||||
{
|
{
|
||||||
return fixp_linear_interpolate(0, 0, priv->max_rpm, U8_MAX,
|
return fixp_linear_interpolate(0, 0, priv->max_rpm, U8_MAX,
|
||||||
|
|
@ -2093,6 +2101,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
|
||||||
static void __exit hp_wmi_bios_remove(struct platform_device *device)
|
static void __exit hp_wmi_bios_remove(struct platform_device *device)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
struct hp_wmi_hwmon_priv *priv;
|
||||||
|
|
||||||
for (i = 0; i < rfkill2_count; i++) {
|
for (i = 0; i < rfkill2_count; i++) {
|
||||||
rfkill_unregister(rfkill2[i].rfkill);
|
rfkill_unregister(rfkill2[i].rfkill);
|
||||||
|
|
@ -2111,6 +2120,10 @@ static void __exit hp_wmi_bios_remove(struct platform_device *device)
|
||||||
rfkill_unregister(wwan_rfkill);
|
rfkill_unregister(wwan_rfkill);
|
||||||
rfkill_destroy(wwan_rfkill);
|
rfkill_destroy(wwan_rfkill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priv = platform_get_drvdata(device);
|
||||||
|
if (priv)
|
||||||
|
cancel_delayed_work_sync(&priv->keep_alive_dwork);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hp_wmi_resume_handler(struct device *device)
|
static int hp_wmi_resume_handler(struct device *device)
|
||||||
|
|
@ -2179,12 +2192,20 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv)
|
||||||
if (is_victus_s_thermal_profile())
|
if (is_victus_s_thermal_profile())
|
||||||
hp_wmi_get_fan_count_userdefine_trigger();
|
hp_wmi_get_fan_count_userdefine_trigger();
|
||||||
ret = hp_wmi_fan_speed_max_set(1);
|
ret = hp_wmi_fan_speed_max_set(1);
|
||||||
return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
schedule_delayed_work(&priv->keep_alive_dwork,
|
||||||
|
secs_to_jiffies(KEEP_ALIVE_DELAY_SECS));
|
||||||
|
return 0;
|
||||||
case PWM_MODE_MANUAL:
|
case PWM_MODE_MANUAL:
|
||||||
if (!is_victus_s_thermal_profile())
|
if (!is_victus_s_thermal_profile())
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
ret = hp_wmi_fan_speed_set(priv, pwm_to_rpm(priv->pwm, priv));
|
ret = hp_wmi_fan_speed_set(priv, pwm_to_rpm(priv->pwm, priv));
|
||||||
return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
schedule_delayed_work(&priv->keep_alive_dwork,
|
||||||
|
secs_to_jiffies(KEEP_ALIVE_DELAY_SECS));
|
||||||
|
return 0;
|
||||||
case PWM_MODE_AUTO:
|
case PWM_MODE_AUTO:
|
||||||
if (is_victus_s_thermal_profile()) {
|
if (is_victus_s_thermal_profile()) {
|
||||||
hp_wmi_get_fan_count_userdefine_trigger();
|
hp_wmi_get_fan_count_userdefine_trigger();
|
||||||
|
|
@ -2192,7 +2213,10 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv)
|
||||||
} else {
|
} else {
|
||||||
ret = hp_wmi_fan_speed_max_set(0);
|
ret = hp_wmi_fan_speed_max_set(0);
|
||||||
}
|
}
|
||||||
return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
cancel_delayed_work_sync(&priv->keep_alive_dwork);
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
/* shouldn't happen */
|
/* shouldn't happen */
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -2336,6 +2360,20 @@ static const struct hwmon_chip_info chip_info = {
|
||||||
.info = info,
|
.info = info,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void hp_wmi_hwmon_keep_alive_handler(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct delayed_work *dwork;
|
||||||
|
struct hp_wmi_hwmon_priv *priv;
|
||||||
|
|
||||||
|
dwork = to_delayed_work(work);
|
||||||
|
priv = container_of(dwork, struct hp_wmi_hwmon_priv, keep_alive_dwork);
|
||||||
|
/*
|
||||||
|
* Re-apply the current hwmon context settings.
|
||||||
|
* NOTE: hp_wmi_apply_fan_settings will handle the re-scheduling.
|
||||||
|
*/
|
||||||
|
hp_wmi_apply_fan_settings(priv);
|
||||||
|
}
|
||||||
|
|
||||||
static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv)
|
static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv)
|
||||||
{
|
{
|
||||||
u8 fan_data[128] = { 0 };
|
u8 fan_data[128] = { 0 };
|
||||||
|
|
@ -2393,6 +2431,8 @@ static int hp_wmi_hwmon_init(void)
|
||||||
return PTR_ERR(hwmon);
|
return PTR_ERR(hwmon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INIT_DELAYED_WORK(&priv->keep_alive_dwork, hp_wmi_hwmon_keep_alive_handler);
|
||||||
|
platform_set_drvdata(hp_wmi_platform_dev, priv);
|
||||||
hp_wmi_apply_fan_settings(priv);
|
hp_wmi_apply_fan_settings(priv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user