All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] hp-wmi: Omen 16-b1xxx (8A13) support + per-fan pwm
@ 2026-05-13 19:39 foobisdweik
  2026-05-13 19:39 ` [PATCH 1/2] platform/x86: hp-wmi: Add support for Omen 16-b1xxx (8A13) foobisdweik
  2026-05-13 19:39 ` [PATCH 2/2] platform/x86: hp-wmi: Expose independent CPU/GPU pwm channels foobisdweik
  0 siblings, 2 replies; 6+ messages in thread
From: foobisdweik @ 2026-05-13 19:39 UTC (permalink / raw)
  To: Hans de Goede, Ilpo Järvinen
  Cc: platform-driver-x86, linux-kernel, foobisdweik

Hi all,

Two patches against drivers/platform/x86/hp/hp-wmi.c. They are
independent but both required to make fan control fully work on
HP OMEN 16-b1xxx laptops.

Patch 1 adds DMI board name 8A13 (OMEN by HP Laptop 16-b1xxx) to
the existing Omen thermal-profile and Victus-S DMI tables. The
firmware exposes the standard Omen PerformanceControl WMI feature
and uses the same legacy EC layout and GM2D/GM2E methods as its
sibling 8A44 (Omen 16-n0xxx). After this patch /sys/firmware/acpi/
platform_profile and the hp hwmon device come up correctly on 8A13.

Patch 2 promotes the per-driver pwm setpoint to a two-element
array so that hp-wmi exposes pwm1 (CPU fan) and pwm2 (GPU fan)
independently on Victus-S-capable boards. The underlying WMI
method (HPWMI_VICTUS_S_FAN_SPEED_SET_QUERY) already takes a
two-byte buffer and the EC honors per-fan setpoints; the driver
just hadn't been wired up that way. This is the standard hwmon
shape for multi-fan systems and makes fan-control tools such as
fancontrol and fan2go work out of the box.

Tested on a stock HP OMEN 16-b1xxx (BIOS F.23, 12th-gen i7-12700H,
RTX 3060) running 7.1-rc2 + these patches: platform_profile
toggles cool/balanced/performance, fan1_input/fan2_input read
independent tachs, and writing pwm1=60 + pwm2=200 simultaneously
drives CPU fan to ~1600 RPM and GPU fan to ~5700 RPM (verified
both via hwmon and direct read of EC offsets 0xB0..0xB3).

Evidence from dmesg:
[    0.000000] DMI: HP OMEN by HP Laptop 16-b1xxx/8A13, BIOS F.23 08/15/2025
[    7.643551] hp_wmi: Registered as platform profile handler

Evidence from sensors (manual control mode):
hp-isa-0000
Adapter: ISA adapter
fan1:        2700 RPM
fan2:        2800 RPM
pwm1:             62%  MANUAL CONTROL
pwm2:             64%  MANUAL CONTROL

foobisdweik (2):
  platform/x86: hp-wmi: Add support for Omen 16-b1xxx (8A13)
  platform/x86: hp-wmi: Expose independent CPU/GPU pwm channels

 drivers/platform/x86/hp/hp-wmi.c | 53 +++++++++++++++++++++++---------
 1 file changed, 38 insertions(+), 15 deletions(-)

--
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] platform/x86: hp-wmi: Add support for Omen 16-b1xxx (8A13)
  2026-05-13 19:39 [PATCH 0/2] hp-wmi: Omen 16-b1xxx (8A13) support + per-fan pwm foobisdweik
@ 2026-05-13 19:39 ` foobisdweik
  2026-05-19 13:58   ` Ilpo Järvinen
  2026-05-20  9:46   ` Krishna Chomal
  2026-05-13 19:39 ` [PATCH 2/2] platform/x86: hp-wmi: Expose independent CPU/GPU pwm channels foobisdweik
  1 sibling, 2 replies; 6+ messages in thread
From: foobisdweik @ 2026-05-13 19:39 UTC (permalink / raw)
  To: Hans de Goede, Ilpo Järvinen
  Cc: platform-driver-x86, linux-kernel, foobisdweik

Add board name 8A13 (OMEN by HP Laptop 16-b1xxx, 12th-gen Intel/RTX 30
series) to the Omen thermal-profile, timed-thermal-profile, and Victus-S
DMI lists.

The 8A13 firmware exposes the standard Omen "PerformanceControl" WMI
feature, uses the legacy EC thermal-profile offset (0x95), and
implements the Victus-S-style GM2D/GM2E WMI methods at EC offsets
0xB0..0xB3 (RPM1..RPM4 tach) and 0x34..0x35 (SRP1/SRP2 setpoints).
This makes it identical in interface to its same-era sibling 8A44
(Omen 16-n0xxx), so reuse omen_v1_legacy_thermal_params.

After this change /sys/firmware/acpi/platform_profile reports
cool/balanced/performance and the hp hwmon device exposes per-fan
tachs plus the manual-mode pwm control on Omen 16-b1xxx.

Signed-off-by: foobisdweik <dweikmferris@gmail.com>
---
 drivers/platform/x86/hp/hp-wmi.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 24c151289dd3..389506a6d2e3 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -157,7 +157,7 @@ static const char * const omen_thermal_profile_boards[] = {
 	"886B", "886C", "88C8", "88CB", "88D1", "88D2", "88F4", "88F5", "88F6",
 	"88F7", "88FD", "88FE", "88FF",
 	"8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB",
-	"8A15", "8A42",
+	"8A13", "8A15", "8A42",
 	"8BAD",
 	"8C58",
 	"8E41",
@@ -177,7 +177,7 @@ static const char * const omen_thermal_profile_force_v0_boards[] = {
  * "balanced" when reaching zero.
  */
 static const char * const omen_timed_thermal_profile_boards[] = {
-	"8A15", "8A42",
+	"8A13", "8A15", "8A42",
 	"8BAD",
 };
 
@@ -189,6 +189,10 @@ static const char * const victus_thermal_profile_boards[] = {
 
 /* DMI Board names of Victus 16-r and Victus 16-s laptops */
 static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = {
+	{
+		.matches = { DMI_MATCH(DMI_BOARD_NAME, "8A13") },
+		.driver_data = (void *)&omen_v1_legacy_thermal_params,
+	},
 	{
 		.matches = { DMI_MATCH(DMI_BOARD_NAME, "8A44") },
 		.driver_data = (void *)&omen_v1_legacy_thermal_params,
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] platform/x86: hp-wmi: Expose independent CPU/GPU pwm channels
  2026-05-13 19:39 [PATCH 0/2] hp-wmi: Omen 16-b1xxx (8A13) support + per-fan pwm foobisdweik
  2026-05-13 19:39 ` [PATCH 1/2] platform/x86: hp-wmi: Add support for Omen 16-b1xxx (8A13) foobisdweik
@ 2026-05-13 19:39 ` foobisdweik
  2026-05-20 10:21   ` Krishna Chomal
  1 sibling, 1 reply; 6+ messages in thread
From: foobisdweik @ 2026-05-13 19:39 UTC (permalink / raw)
  To: Hans de Goede, Ilpo Järvinen
  Cc: platform-driver-x86, linux-kernel, foobisdweik

The Victus-S WMI fan-speed-set query (HPWMI_VICTUS_S_FAN_SPEED_SET_QUERY,
GM2E in firmware) takes a two-byte buffer [cpu, gpu] and writes the
values to EC SRP1/SRP2 setpoints independently. The driver however drove
both fans from a single hwmon pwm1 attribute, with the GPU value
derived as cpu + priv->gpu_delta from the fan table. This makes
asymmetric fan curves (common ask: GPU fan louder than CPU under
heavy gaming load) impossible from userspace fan-control tools that
expect one pwm attribute per fan.

Promote priv->pwm to a two-element array, add a second pwm hwmon
channel, and extend hp_wmi_hwmon_write() / hp_wmi_apply_fan_settings()
to drive the per-channel setpoints through GM2E.

The U8_MAX sentinel in hp_wmi_fan_speed_set() selects the new
per-fan path; existing callers using HP_FAN_SPEED_AUTOMATIC or a
direct rpm value keep their behavior. The second pwm channel is only
visible on Victus-S-capable boards, since other HP laptops still use
the legacy single-fan WMI commands.

Tested on OMEN by HP Laptop 16-b1xxx (8A13): writing pwm1=60, pwm2=200
in manual mode drives CPU fan to ~1600 RPM and GPU fan to ~5700 RPM
simultaneously, verified via fan1_input/fan2_input tachs and direct
read of EC offsets 0xB0..0xB3.

Signed-off-by: foobisdweik <dweikmferris@gmail.com>
---
 drivers/platform/x86/hp/hp-wmi.c | 45 +++++++++++++++++++++++---------
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 389506a6d2e3..40eb3715583a 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -486,7 +486,7 @@ struct hp_wmi_hwmon_priv {
 	u8 max_rpm;
 	int gpu_delta;
 	u8 mode;
-	u8 pwm;
+	u8 pwm[2];
 	struct delayed_work keep_alive_dwork;
 };
 
@@ -822,12 +822,18 @@ static int hp_wmi_fan_speed_set(struct hp_wmi_hwmon_priv *priv, u8 speed)
 	fan_speed[GPU_FAN] = speed;
 
 	/*
-	 * GPU fan speed is always a little higher than CPU fan speed, we fetch
-	 * this delta value from the fan table during hwmon init.
-	 * Exception: Speed is set to HP_FAN_SPEED_AUTOMATIC, to revert to
-	 * automatic mode.
+	 * Pass-through value U8_MAX: drive each fan from its own
+	 * priv->pwm[] setpoint converted via pwm_to_rpm(). Used by the
+	 * hwmon pwm1/pwm2 path that allows independent CPU/GPU fan control.
+	 *
+	 * Otherwise: GPU fan speed is always a little higher than CPU fan
+	 * speed; we fetch this delta from the fan table during hwmon init.
+	 * Exception: HP_FAN_SPEED_AUTOMATIC reverts to automatic mode.
 	 */
-	if (speed != HP_FAN_SPEED_AUTOMATIC) {
+	if (speed == U8_MAX) {
+		fan_speed[CPU_FAN] = pwm_to_rpm(priv->pwm[CPU_FAN], priv);
+		fan_speed[GPU_FAN] = pwm_to_rpm(priv->pwm[GPU_FAN], priv);
+	} else if (speed != HP_FAN_SPEED_AUTOMATIC) {
 		gpu_speed = speed + priv->gpu_delta;
 		fan_speed[GPU_FAN] = clamp_val(gpu_speed, 0, U8_MAX);
 	}
@@ -2398,7 +2404,7 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv)
 	case PWM_MODE_MANUAL:
 		if (!is_victus_s_thermal_profile())
 			return -EOPNOTSUPP;
-		ret = hp_wmi_fan_speed_set(priv, pwm_to_rpm(priv->pwm, priv));
+		ret = hp_wmi_fan_speed_set(priv, U8_MAX);
 		if (ret < 0)
 			return ret;
 		mod_delayed_work(system_wq, &priv->keep_alive_dwork,
@@ -2429,6 +2435,12 @@ static umode_t hp_wmi_hwmon_is_visible(const void *data,
 {
 	switch (type) {
 	case hwmon_pwm:
+		/*
+		 * Second pwm channel only exists on Victus-S-style boards
+		 * which expose an independent GPU fan setpoint.
+		 */
+		if (channel == 1 && !is_victus_s_thermal_profile())
+			return 0;
 		if (attr == hwmon_pwm_input && !is_victus_s_thermal_profile())
 			return 0;
 		return 0644;
@@ -2514,7 +2526,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
 			/* ensure PWM input is within valid fan speeds */
 			rpm = pwm_to_rpm(val, priv);
 			rpm = clamp_val(rpm, priv->min_rpm, priv->max_rpm);
-			priv->pwm = rpm_to_pwm(rpm, priv);
+			priv->pwm[channel] = rpm_to_pwm(rpm, priv);
 			return hp_wmi_apply_fan_settings(priv);
 		}
 		switch (val) {
@@ -2525,13 +2537,18 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
 			if (!is_victus_s_thermal_profile())
 				return -EOPNOTSUPP;
 			/*
-			 * When switching to manual mode, set fan speed to
-			 * current RPM values to ensure a smooth transition.
+			 * When switching to manual mode, seed each per-fan
+			 * setpoint from its current measured RPM so the
+			 * transition is smooth.
 			 */
-			rpm = hp_wmi_get_fan_speed_victus_s(channel);
+			rpm = hp_wmi_get_fan_speed_victus_s(CPU_FAN);
+			if (rpm < 0)
+				return rpm;
+			priv->pwm[CPU_FAN] = rpm_to_pwm(rpm / 100, priv);
+			rpm = hp_wmi_get_fan_speed_victus_s(GPU_FAN);
 			if (rpm < 0)
 				return rpm;
-			priv->pwm = rpm_to_pwm(rpm / 100, priv);
+			priv->pwm[GPU_FAN] = rpm_to_pwm(rpm / 100, priv);
 			priv->mode = PWM_MODE_MANUAL;
 			return hp_wmi_apply_fan_settings(priv);
 		case PWM_MODE_AUTO:
@@ -2547,7 +2564,9 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
 
 static const struct hwmon_channel_info * const info[] = {
 	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT),
-	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_ENABLE | HWMON_PWM_INPUT),
+	HWMON_CHANNEL_INFO(pwm,
+			   HWMON_PWM_ENABLE | HWMON_PWM_INPUT,
+			   HWMON_PWM_ENABLE | HWMON_PWM_INPUT),
 	NULL
 };
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] platform/x86: hp-wmi: Add support for Omen 16-b1xxx (8A13)
  2026-05-13 19:39 ` [PATCH 1/2] platform/x86: hp-wmi: Add support for Omen 16-b1xxx (8A13) foobisdweik
@ 2026-05-19 13:58   ` Ilpo Järvinen
  2026-05-20  9:46   ` Krishna Chomal
  1 sibling, 0 replies; 6+ messages in thread
From: Ilpo Järvinen @ 2026-05-19 13:58 UTC (permalink / raw)
  To: foobisdweik; +Cc: Hans de Goede, platform-driver-x86, LKML

On Wed, 13 May 2026, foobisdweik wrote:

> Add board name 8A13 (OMEN by HP Laptop 16-b1xxx, 12th-gen Intel/RTX 30
> series) to the Omen thermal-profile, timed-thermal-profile, and Victus-S
> DMI lists.
> 
> The 8A13 firmware exposes the standard Omen "PerformanceControl" WMI
> feature, uses the legacy EC thermal-profile offset (0x95), and
> implements the Victus-S-style GM2D/GM2E WMI methods at EC offsets
> 0xB0..0xB3 (RPM1..RPM4 tach) and 0x34..0x35 (SRP1/SRP2 setpoints).
> This makes it identical in interface to its same-era sibling 8A44
> (Omen 16-n0xxx), so reuse omen_v1_legacy_thermal_params.
> 
> After this change /sys/firmware/acpi/platform_profile reports
> cool/balanced/performance and the hp hwmon device exposes per-fan
> tachs plus the manual-mode pwm control on Omen 16-b1xxx.
> 
> Signed-off-by: foobisdweik <dweikmferris@gmail.com>

Hi,

Thanks for the patch, but we're not allowed to take in patches with sign 
off lines using nicknames or pseudo names (please see 
Documentation/process/submitting-patches.rst).

> ---
>  drivers/platform/x86/hp/hp-wmi.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
> index 24c151289dd3..389506a6d2e3 100644
> --- a/drivers/platform/x86/hp/hp-wmi.c
> +++ b/drivers/platform/x86/hp/hp-wmi.c
> @@ -157,7 +157,7 @@ static const char * const omen_thermal_profile_boards[] = {
>  	"886B", "886C", "88C8", "88CB", "88D1", "88D2", "88F4", "88F5", "88F6",
>  	"88F7", "88FD", "88FE", "88FF",
>  	"8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB",
> -	"8A15", "8A42",
> +	"8A13", "8A15", "8A42",
>  	"8BAD",
>  	"8C58",
>  	"8E41",
> @@ -177,7 +177,7 @@ static const char * const omen_thermal_profile_force_v0_boards[] = {
>   * "balanced" when reaching zero.
>   */
>  static const char * const omen_timed_thermal_profile_boards[] = {
> -	"8A15", "8A42",
> +	"8A13", "8A15", "8A42",
>  	"8BAD",
>  };
>  
> @@ -189,6 +189,10 @@ static const char * const victus_thermal_profile_boards[] = {
>  
>  /* DMI Board names of Victus 16-r and Victus 16-s laptops */
>  static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = {
> +	{
> +		.matches = { DMI_MATCH(DMI_BOARD_NAME, "8A13") },
> +		.driver_data = (void *)&omen_v1_legacy_thermal_params,
> +	},

I'll soon be pushing out review-ilpo-fixes branch, which will add 8902 
here. In order to avoid conflict with it, please base this change on top 
of it.

>  	{
>  		.matches = { DMI_MATCH(DMI_BOARD_NAME, "8A44") },
>  		.driver_data = (void *)&omen_v1_legacy_thermal_params,
> 

-- 
 i.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] platform/x86: hp-wmi: Add support for Omen 16-b1xxx (8A13)
  2026-05-13 19:39 ` [PATCH 1/2] platform/x86: hp-wmi: Add support for Omen 16-b1xxx (8A13) foobisdweik
  2026-05-19 13:58   ` Ilpo Järvinen
@ 2026-05-20  9:46   ` Krishna Chomal
  1 sibling, 0 replies; 6+ messages in thread
From: Krishna Chomal @ 2026-05-20  9:46 UTC (permalink / raw)
  To: foobisdweik
  Cc: Hans de Goede, Ilpo Järvinen, platform-driver-x86,
	linux-kernel

On Wed, May 13, 2026 at 12:39:15PM -0700, foobisdweik wrote:
>Add board name 8A13 (OMEN by HP Laptop 16-b1xxx, 12th-gen Intel/RTX 30
>series) to the Omen thermal-profile, timed-thermal-profile, and Victus-S
>DMI lists.
>

The DMI lists are exclusively checked at every reference so adding to
Victus-S seems sufficient, as addition to omen thermal-profile and
timed-thermal-profile would not make a difference.

>The 8A13 firmware exposes the standard Omen "PerformanceControl" WMI
>feature, uses the legacy EC thermal-profile offset (0x95), and
>implements the Victus-S-style GM2D/GM2E WMI methods at EC offsets
>0xB0..0xB3 (RPM1..RPM4 tach) and 0x34..0x35 (SRP1/SRP2 setpoints).
>This makes it identical in interface to its same-era sibling 8A44
>(Omen 16-n0xxx), so reuse omen_v1_legacy_thermal_params.
>
>After this change /sys/firmware/acpi/platform_profile reports
>cool/balanced/performance and the hp hwmon device exposes per-fan
>tachs plus the manual-mode pwm control on Omen 16-b1xxx.
>
>Signed-off-by: foobisdweik <dweikmferris@gmail.com>
>---
> drivers/platform/x86/hp/hp-wmi.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
>index 24c151289dd3..389506a6d2e3 100644
>--- a/drivers/platform/x86/hp/hp-wmi.c
>+++ b/drivers/platform/x86/hp/hp-wmi.c
>@@ -157,7 +157,7 @@ static const char * const omen_thermal_profile_boards[] = {
> 	"886B", "886C", "88C8", "88CB", "88D1", "88D2", "88F4", "88F5", "88F6",
> 	"88F7", "88FD", "88FE", "88FF",
> 	"8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB",
>-	"8A15", "8A42",
>+	"8A13", "8A15", "8A42",
> 	"8BAD",
> 	"8C58",
> 	"8E41",
>@@ -177,7 +177,7 @@ static const char * const omen_thermal_profile_force_v0_boards[] = {
>  * "balanced" when reaching zero.
>  */
> static const char * const omen_timed_thermal_profile_boards[] = {
>-	"8A15", "8A42",
>+	"8A13", "8A15", "8A42",
> 	"8BAD",
> };
>
>@@ -189,6 +189,10 @@ static const char * const victus_thermal_profile_boards[] = {
>
> /* DMI Board names of Victus 16-r and Victus 16-s laptops */
> static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = {
>+	{
>+		.matches = { DMI_MATCH(DMI_BOARD_NAME, "8A13") },
>+		.driver_data = (void *)&omen_v1_legacy_thermal_params,
>+	},
> 	{
> 		.matches = { DMI_MATCH(DMI_BOARD_NAME, "8A44") },
> 		.driver_data = (void *)&omen_v1_legacy_thermal_params,
>-- 
>2.54.0
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] platform/x86: hp-wmi: Expose independent CPU/GPU pwm channels
  2026-05-13 19:39 ` [PATCH 2/2] platform/x86: hp-wmi: Expose independent CPU/GPU pwm channels foobisdweik
@ 2026-05-20 10:21   ` Krishna Chomal
  0 siblings, 0 replies; 6+ messages in thread
From: Krishna Chomal @ 2026-05-20 10:21 UTC (permalink / raw)
  To: foobisdweik
  Cc: Hans de Goede, Ilpo Järvinen, platform-driver-x86,
	linux-kernel

On Wed, May 13, 2026 at 12:39:16PM -0700, foobisdweik wrote:
>The Victus-S WMI fan-speed-set query (HPWMI_VICTUS_S_FAN_SPEED_SET_QUERY,
>GM2E in firmware) takes a two-byte buffer [cpu, gpu] and writes the
>values to EC SRP1/SRP2 setpoints independently. The driver however drove
>both fans from a single hwmon pwm1 attribute, with the GPU value
>derived as cpu + priv->gpu_delta from the fan table. This makes
>asymmetric fan curves (common ask: GPU fan louder than CPU under
>heavy gaming load) impossible from userspace fan-control tools that
>expect one pwm attribute per fan.
>
>Promote priv->pwm to a two-element array, add a second pwm hwmon
>channel, and extend hp_wmi_hwmon_write() / hp_wmi_apply_fan_settings()
>to drive the per-channel setpoints through GM2E.
>
>The U8_MAX sentinel in hp_wmi_fan_speed_set() selects the new
>per-fan path; existing callers using HP_FAN_SPEED_AUTOMATIC or a
>direct rpm value keep their behavior. The second pwm channel is only
>visible on Victus-S-capable boards, since other HP laptops still use
>the legacy single-fan WMI commands.
>
>Tested on OMEN by HP Laptop 16-b1xxx (8A13): writing pwm1=60, pwm2=200
>in manual mode drives CPU fan to ~1600 RPM and GPU fan to ~5700 RPM
>simultaneously, verified via fan1_input/fan2_input tachs and direct
>read of EC offsets 0xB0..0xB3.
>
>Signed-off-by: foobisdweik <dweikmferris@gmail.com>
>---
> drivers/platform/x86/hp/hp-wmi.c | 45 +++++++++++++++++++++++---------
> 1 file changed, 32 insertions(+), 13 deletions(-)
>
>diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
>index 389506a6d2e3..40eb3715583a 100644
>--- a/drivers/platform/x86/hp/hp-wmi.c
>+++ b/drivers/platform/x86/hp/hp-wmi.c
>@@ -486,7 +486,7 @@ struct hp_wmi_hwmon_priv {
> 	u8 max_rpm;
> 	int gpu_delta;
> 	u8 mode;
>-	u8 pwm;
>+	u8 pwm[2];
> 	struct delayed_work keep_alive_dwork;
> };
>
>@@ -822,12 +822,18 @@ static int hp_wmi_fan_speed_set(struct hp_wmi_hwmon_priv *priv, u8 speed)
> 	fan_speed[GPU_FAN] = speed;
>
> 	/*
>-	 * GPU fan speed is always a little higher than CPU fan speed, we fetch
>-	 * this delta value from the fan table during hwmon init.
>-	 * Exception: Speed is set to HP_FAN_SPEED_AUTOMATIC, to revert to
>-	 * automatic mode.
>+	 * Pass-through value U8_MAX: drive each fan from its own
>+	 * priv->pwm[] setpoint converted via pwm_to_rpm(). Used by the
>+	 * hwmon pwm1/pwm2 path that allows independent CPU/GPU fan control.
>+	 *
>+	 * Otherwise: GPU fan speed is always a little higher than CPU fan
>+	 * speed; we fetch this delta from the fan table during hwmon init.
>+	 * Exception: HP_FAN_SPEED_AUTOMATIC reverts to automatic mode.
> 	 */
>-	if (speed != HP_FAN_SPEED_AUTOMATIC) {
>+	if (speed == U8_MAX) {
>+		fan_speed[CPU_FAN] = pwm_to_rpm(priv->pwm[CPU_FAN], priv);
>+		fan_speed[GPU_FAN] = pwm_to_rpm(priv->pwm[GPU_FAN], priv);
>+	} else if (speed != HP_FAN_SPEED_AUTOMATIC) {
> 		gpu_speed = speed + priv->gpu_delta;
> 		fan_speed[GPU_FAN] = clamp_val(gpu_speed, 0, U8_MAX);
> 	}

Currently, there are 2 callers for hp_wmi_fan_speed_set:

1. hp_wmi_fan_speed_reset() -> calls via speed = HP_FAN_SPEED_AUTOMATIC,
    and
2. hp_wmi_apply_fan_settings() -> calls via speed = U8_MAX (as updated
    by you)

So this else-if block is effectively never executed, which in turn means
that gpu_delta is also now redundant.

>@@ -2398,7 +2404,7 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv)
> 	case PWM_MODE_MANUAL:
> 		if (!is_victus_s_thermal_profile())
> 			return -EOPNOTSUPP;
>-		ret = hp_wmi_fan_speed_set(priv, pwm_to_rpm(priv->pwm, priv));
>+		ret = hp_wmi_fan_speed_set(priv, U8_MAX);

I think you could avoid passing the sentinel argument (speed) and
directly update priv->pwm[] in the caller: hp_wmi_fan_speed_reset()

> 		if (ret < 0)
> 			return ret;
> 		mod_delayed_work(system_wq, &priv->keep_alive_dwork,
>@@ -2429,6 +2435,12 @@ static umode_t hp_wmi_hwmon_is_visible(const void *data,
> {
> 	switch (type) {
> 	case hwmon_pwm:
>+		/*
>+		 * Second pwm channel only exists on Victus-S-style boards
>+		 * which expose an independent GPU fan setpoint.
>+		 */
>+		if (channel == 1 && !is_victus_s_thermal_profile())
>+			return 0;

Technically, the fan table has a dedicated field .num_fans (see
struct victus_s_fan_table_header), so there is a possibility that some
Victus-S-style device may not have second fan for pwm channel. But at
least for the current entries, this is not the case, so I guess it would
be safe to keep it this way.

> 		if (attr == hwmon_pwm_input && !is_victus_s_thermal_profile())
> 			return 0;
> 		return 0644;
>@@ -2514,7 +2526,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
> 			/* ensure PWM input is within valid fan speeds */
> 			rpm = pwm_to_rpm(val, priv);
> 			rpm = clamp_val(rpm, priv->min_rpm, priv->max_rpm);
>-			priv->pwm = rpm_to_pwm(rpm, priv);
>+			priv->pwm[channel] = rpm_to_pwm(rpm, priv);
> 			return hp_wmi_apply_fan_settings(priv);
> 		}
> 		switch (val) {
>@@ -2525,13 +2537,18 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
> 			if (!is_victus_s_thermal_profile())
> 				return -EOPNOTSUPP;
> 			/*
>-			 * When switching to manual mode, set fan speed to
>-			 * current RPM values to ensure a smooth transition.
>+			 * When switching to manual mode, seed each per-fan
>+			 * setpoint from its current measured RPM so the
>+			 * transition is smooth.
> 			 */
>-			rpm = hp_wmi_get_fan_speed_victus_s(channel);
>+			rpm = hp_wmi_get_fan_speed_victus_s(CPU_FAN);
>+			if (rpm < 0)
>+				return rpm;
>+			priv->pwm[CPU_FAN] = rpm_to_pwm(rpm / 100, priv);
>+			rpm = hp_wmi_get_fan_speed_victus_s(GPU_FAN);
> 			if (rpm < 0)
> 				return rpm;
>-			priv->pwm = rpm_to_pwm(rpm / 100, priv);
>+			priv->pwm[GPU_FAN] = rpm_to_pwm(rpm / 100, priv);
> 			priv->mode = PWM_MODE_MANUAL;
> 			return hp_wmi_apply_fan_settings(priv);
> 		case PWM_MODE_AUTO:
>@@ -2547,7 +2564,9 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
>
> static const struct hwmon_channel_info * const info[] = {
> 	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT),
>-	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_ENABLE | HWMON_PWM_INPUT),
>+	HWMON_CHANNEL_INFO(pwm,
>+			   HWMON_PWM_ENABLE | HWMON_PWM_INPUT,
>+			   HWMON_PWM_ENABLE | HWMON_PWM_INPUT),

I think you can take this opportunity to explore adding
fanX_{min,max,input} to hwmon as well.

> 	NULL
> };
>
>-- 
>2.54.0
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-05-20 10:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-13 19:39 [PATCH 0/2] hp-wmi: Omen 16-b1xxx (8A13) support + per-fan pwm foobisdweik
2026-05-13 19:39 ` [PATCH 1/2] platform/x86: hp-wmi: Add support for Omen 16-b1xxx (8A13) foobisdweik
2026-05-19 13:58   ` Ilpo Järvinen
2026-05-20  9:46   ` Krishna Chomal
2026-05-13 19:39 ` [PATCH 2/2] platform/x86: hp-wmi: Expose independent CPU/GPU pwm channels foobisdweik
2026-05-20 10:21   ` Krishna Chomal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.