hwmon: (arctic_fan_controller) Default PWM cache to MCU 40%

The device has no GET_REPORT and every OUT report carries all 10
channels, so the cache has to start at some value. Starting at 0
means the first sysfs write to a single channel also sends 0% on
the other nine.

The MCU factory default is 40%. Initialize pwm_duty[] to 102 (40%
on the 0-255 sysfs scale) at probe and on reset-resume. Any initial
cache can be stale if the module is reloaded without a device
reset. 40% matches the hardware after power-on or power-loss
resume, and a first single-channel write leaves the fans running
at a safe speed.

PWM is still not taken from periodic IN reports: the device is
manual-only and the host cache stays authoritative after the first
successful write.

Signed-off-by: Aureo Serrano de Souza <aureo.serrano@arctic.de>
Link: https://patch.msgid.link/20260910050401.279868-2-aureo.serrano@arctic.de
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Aureo Serrano de Souza 2026-09-10 13:03:59 +08:00 committed by Guenter Roeck
parent 6c2437800d
commit d17832c1c9
2 changed files with 22 additions and 20 deletions

View File

@ -29,18 +29,16 @@ Usage notes
Since it is a USB device, hotplug is supported. The device is autodetected.
The device does not support GET_REPORT, so the driver cannot read back the
current hardware PWM state at probe time. The cached PWM values (readable
via pwm[1-10]) start at 0 and reflect only values that have been
successfully written. Because each OUT report carries all 10 channel values,
writing a single channel also sends the cached values for all other channels.
Users should set all channels to the desired values before relying on the
cached state.
current hardware PWM state at probe time. Each OUT report carries all 10
channels, so pwm[1-10] is a host cache. It starts at the MCU factory
default of 40% (sysfs 102). After a successful write, the cache reflects
that value. Users should set all channels to the desired values before
relying on the cached state.
On system suspend, the device may lose power and reset its PWM channels to
hardware defaults. The driver clears its cached duty values on resume so
that reads reflect the unknown hardware state rather than stale pre-suspend
values. Userspace is responsible for re-applying the desired duty cycles
after resume.
On system suspend, the device may lose power and reset PWM to the factory
default. The driver restores the cache to 40% on resume. If the device
kept power across suspend, userspace should re-apply the desired duty
cycles.
Sysfs entries
-------------
@ -51,6 +49,6 @@ pwm[1-10] PWM duty cycle (0-255). Write: sends an OUT report setting the
duty cycle (scaled from 0-255 to 0-100% for the device);
the cached value is updated only after the device ACKs the
command with a success status. Read: returns the last
successfully written value; initialized to 0 at driver load
and after resume (hardware state unknown).
successfully written value; initialized to 102 (40%) at
driver load and after resume (MCU factory default).
================ ==============================================================

View File

@ -35,6 +35,8 @@
* Measured over 500 iterations: max ~563 ms. Keep 1 s as margin.
*/
#define ARCTIC_ACK_TIMEOUT_MS 1000
/* MCU factory default; 40% of 0-255 is 102. */
#define ARCTIC_PWM_DEFAULT 102
struct arctic_fan_data {
struct hid_device *hdev;
@ -164,7 +166,7 @@ static int arctic_fan_write(struct device *dev, enum hwmon_sensor_types type,
/*
* Build the buffer and arm write_pending under in_report_lock so that
* reset_resume() cannot clear pwm_duty[] between the pwm_duty[] read
* reset_resume() cannot replace pwm_duty[] between the pwm_duty[] read
* and the buffer write, and raw_event() cannot deliver a stale ACK
* from a previous write into this write's completion.
*
@ -256,14 +258,14 @@ static int arctic_fan_reset_resume(struct hid_device *hdev)
unsigned long flags;
/*
* The device resets its PWM channels to hardware defaults on power
* loss during suspend. Clear the cached duty values so they reflect
* the unknown hardware state, consistent with probe-time behaviour
* (the device has no GET_REPORT support). Hold in_report_lock so
* this does not race with a concurrent pwm read or write callback.
* The device resets its PWM channels to the MCU factory default
* (40%) on power loss during suspend. Restore the cache to that
* same default, consistent with probe-time behaviour (the device
* has no GET_REPORT support). Hold in_report_lock so this does
* not race with a concurrent pwm read or write callback.
*/
spin_lock_irqsave(&priv->in_report_lock, flags);
memset(priv->pwm_duty, 0, sizeof(priv->pwm_duty));
memset(priv->pwm_duty, ARCTIC_PWM_DEFAULT, sizeof(priv->pwm_duty));
spin_unlock_irqrestore(&priv->in_report_lock, flags);
return 0;
}
@ -288,6 +290,8 @@ static int arctic_fan_probe(struct hid_device *hdev,
priv->hdev = hdev;
spin_lock_init(&priv->in_report_lock);
init_completion(&priv->in_report_received);
/* Same MCU factory default as reset_resume(); see ARCTIC_PWM_DEFAULT above. */
memset(priv->pwm_duty, ARCTIC_PWM_DEFAULT, sizeof(priv->pwm_duty));
hid_set_drvdata(hdev, priv);
ret = hid_hw_start(hdev, HID_CONNECT_DRIVER);