Skip to content

Commit 6c00f29

Browse files
joshuagrishamrafaeljw
authored andcommitted
ACPI: fan: Add fan speed reporting for fans with only _FST
Add support for ACPI fans with _FST to report their speed even if they do not support fan control. As suggested by Armin Wolf [1] and per the Windows Thermal Management Design Guide [2], Samsung Galaxy Book series devices (and possibly many more devices where the Windows guide was strictly followed) only implement the _FST method and do not support ACPI-based fan control. Currently, these fans are not supported by the kernel driver but this patch will make some very small adjustments to allow them to be supported. This patch is tested and working for me on a Samsung Galaxy Book2 Pro whose DSDT (and several other Samsung Galaxy Book series notebooks which currently have the same issue) can be found at [3]. Link: https://lore.kernel.org/platform-driver-x86/53c5075b-1967-45d0-937f-463912dd966d@gmx.de [1] Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/design-guide [2] Link: https://github.com/joshuagrisham/samsung-galaxybook-extras/tree/8e3087a06b8bdcdfdd081367af4b744a56cc4ee9/dsdt [3] Signed-off-by: Joshua Grisham <josh@joshuagrisham.com> Reviewed-by: Armin Wolf <W_Armin@gmx.de> Link: https://patch.msgid.link/20250222094407.9753-1-josh@joshuagrisham.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent d082ecb commit 6c00f29

File tree

4 files changed

+49
-22
lines changed

4 files changed

+49
-22
lines changed

drivers/acpi/fan.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct acpi_fan_fst {
4949

5050
struct acpi_fan {
5151
bool acpi4;
52+
bool has_fst;
5253
struct acpi_fan_fif fif;
5354
struct acpi_fan_fps *fps;
5455
int fps_count;

drivers/acpi/fan_attr.c

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,6 @@ int acpi_fan_create_attributes(struct acpi_device *device)
7575
struct acpi_fan *fan = acpi_driver_data(device);
7676
int i, status;
7777

78-
sysfs_attr_init(&fan->fine_grain_control.attr);
79-
fan->fine_grain_control.show = show_fine_grain_control;
80-
fan->fine_grain_control.store = NULL;
81-
fan->fine_grain_control.attr.name = "fine_grain_control";
82-
fan->fine_grain_control.attr.mode = 0444;
83-
status = sysfs_create_file(&device->dev.kobj, &fan->fine_grain_control.attr);
84-
if (status)
85-
return status;
86-
8778
/* _FST is present if we are here */
8879
sysfs_attr_init(&fan->fst_speed.attr);
8980
fan->fst_speed.show = show_fan_speed;
@@ -92,7 +83,19 @@ int acpi_fan_create_attributes(struct acpi_device *device)
9283
fan->fst_speed.attr.mode = 0444;
9384
status = sysfs_create_file(&device->dev.kobj, &fan->fst_speed.attr);
9485
if (status)
95-
goto rem_fine_grain_attr;
86+
return status;
87+
88+
if (!fan->acpi4)
89+
return 0;
90+
91+
sysfs_attr_init(&fan->fine_grain_control.attr);
92+
fan->fine_grain_control.show = show_fine_grain_control;
93+
fan->fine_grain_control.store = NULL;
94+
fan->fine_grain_control.attr.name = "fine_grain_control";
95+
fan->fine_grain_control.attr.mode = 0444;
96+
status = sysfs_create_file(&device->dev.kobj, &fan->fine_grain_control.attr);
97+
if (status)
98+
goto rem_fst_attr;
9699

97100
for (i = 0; i < fan->fps_count; ++i) {
98101
struct acpi_fan_fps *fps = &fan->fps[i];
@@ -109,18 +112,18 @@ int acpi_fan_create_attributes(struct acpi_device *device)
109112

110113
for (j = 0; j < i; ++j)
111114
sysfs_remove_file(&device->dev.kobj, &fan->fps[j].dev_attr.attr);
112-
goto rem_fst_attr;
115+
goto rem_fine_grain_attr;
113116
}
114117
}
115118

116119
return 0;
117120

118-
rem_fst_attr:
119-
sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);
120-
121121
rem_fine_grain_attr:
122122
sysfs_remove_file(&device->dev.kobj, &fan->fine_grain_control.attr);
123123

124+
rem_fst_attr:
125+
sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);
126+
124127
return status;
125128
}
126129

@@ -129,9 +132,13 @@ void acpi_fan_delete_attributes(struct acpi_device *device)
129132
struct acpi_fan *fan = acpi_driver_data(device);
130133
int i;
131134

135+
sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);
136+
137+
if (!fan->acpi4)
138+
return;
139+
132140
for (i = 0; i < fan->fps_count; ++i)
133141
sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
134142

135-
sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);
136143
sysfs_remove_file(&device->dev.kobj, &fan->fine_grain_control.attr);
137144
}

drivers/acpi/fan_core.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,16 @@ static const struct thermal_cooling_device_ops fan_cooling_ops = {
203203
* --------------------------------------------------------------------------
204204
*/
205205

206+
static bool acpi_fan_has_fst(struct acpi_device *device)
207+
{
208+
return acpi_has_method(device->handle, "_FST");
209+
}
210+
206211
static bool acpi_fan_is_acpi4(struct acpi_device *device)
207212
{
208213
return acpi_has_method(device->handle, "_FIF") &&
209214
acpi_has_method(device->handle, "_FPS") &&
210-
acpi_has_method(device->handle, "_FSL") &&
211-
acpi_has_method(device->handle, "_FST");
215+
acpi_has_method(device->handle, "_FSL");
212216
}
213217

214218
static int acpi_fan_get_fif(struct acpi_device *device)
@@ -327,25 +331,32 @@ static int acpi_fan_probe(struct platform_device *pdev)
327331
device->driver_data = fan;
328332
platform_set_drvdata(pdev, fan);
329333

330-
if (acpi_fan_is_acpi4(device)) {
334+
if (acpi_fan_has_fst(device)) {
335+
fan->has_fst = true;
336+
fan->acpi4 = acpi_fan_is_acpi4(device);
337+
}
338+
339+
if (fan->acpi4) {
331340
result = acpi_fan_get_fif(device);
332341
if (result)
333342
return result;
334343

335344
result = acpi_fan_get_fps(device);
336345
if (result)
337346
return result;
347+
}
338348

349+
if (fan->has_fst) {
339350
result = devm_acpi_fan_create_hwmon(device);
340351
if (result)
341352
return result;
342353

343354
result = acpi_fan_create_attributes(device);
344355
if (result)
345356
return result;
357+
}
346358

347-
fan->acpi4 = true;
348-
} else {
359+
if (!fan->acpi4) {
349360
result = acpi_device_update_power(device, NULL);
350361
if (result) {
351362
dev_err(&device->dev, "Failed to set initial power state\n");
@@ -391,7 +402,7 @@ static int acpi_fan_probe(struct platform_device *pdev)
391402
err_unregister:
392403
thermal_cooling_device_unregister(cdev);
393404
err_end:
394-
if (fan->acpi4)
405+
if (fan->has_fst)
395406
acpi_fan_delete_attributes(device);
396407

397408
return result;
@@ -401,7 +412,7 @@ static void acpi_fan_remove(struct platform_device *pdev)
401412
{
402413
struct acpi_fan *fan = platform_get_drvdata(pdev);
403414

404-
if (fan->acpi4) {
415+
if (fan->has_fst) {
405416
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
406417

407418
acpi_fan_delete_attributes(device);

drivers/acpi/fan_hwmon.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_
4343
case hwmon_fan_input:
4444
return 0444;
4545
case hwmon_fan_target:
46+
/* Only acpi4 fans support fan control. */
47+
if (!fan->acpi4)
48+
return 0;
49+
4650
/*
4751
* When in fine grain control mode, not every fan control value
4852
* has an associated fan performance state.
@@ -57,6 +61,10 @@ static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_
5761
case hwmon_power:
5862
switch (attr) {
5963
case hwmon_power_input:
64+
/* Only acpi4 fans support fan control. */
65+
if (!fan->acpi4)
66+
return 0;
67+
6068
/*
6169
* When in fine grain control mode, not every fan control value
6270
* has an associated fan performance state.

0 commit comments

Comments
 (0)