Commit | Line | Data |
---|---|---|
00ae053a SP |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * fan_attr.c - Create extra attributes for ACPI Fan driver | |
4 | * | |
5 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> | |
6 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | |
7 | * Copyright (C) 2022 Intel Corporation. All rights reserved. | |
8 | */ | |
9 | ||
10 | #include <linux/kernel.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/init.h> | |
13 | #include <linux/acpi.h> | |
14 | ||
15 | #include "fan.h" | |
16 | ||
17 | MODULE_LICENSE("GPL"); | |
18 | ||
19 | static ssize_t show_state(struct device *dev, struct device_attribute *attr, char *buf) | |
20 | { | |
21 | struct acpi_fan_fps *fps = container_of(attr, struct acpi_fan_fps, dev_attr); | |
22 | int count; | |
23 | ||
24 | if (fps->control == 0xFFFFFFFF || fps->control > 100) | |
25 | count = scnprintf(buf, PAGE_SIZE, "not-defined:"); | |
26 | else | |
27 | count = scnprintf(buf, PAGE_SIZE, "%lld:", fps->control); | |
28 | ||
29 | if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9) | |
64ee2528 | 30 | count += sysfs_emit_at(buf, count, "not-defined:"); |
00ae053a | 31 | else |
64ee2528 | 32 | count += sysfs_emit_at(buf, count, "%lld:", fps->trip_point); |
00ae053a SP |
33 | |
34 | if (fps->speed == 0xFFFFFFFF) | |
64ee2528 | 35 | count += sysfs_emit_at(buf, count, "not-defined:"); |
00ae053a | 36 | else |
64ee2528 | 37 | count += sysfs_emit_at(buf, count, "%lld:", fps->speed); |
00ae053a SP |
38 | |
39 | if (fps->noise_level == 0xFFFFFFFF) | |
64ee2528 | 40 | count += sysfs_emit_at(buf, count, "not-defined:"); |
00ae053a | 41 | else |
64ee2528 | 42 | count += sysfs_emit_at(buf, count, "%lld:", fps->noise_level * 100); |
00ae053a SP |
43 | |
44 | if (fps->power == 0xFFFFFFFF) | |
64ee2528 | 45 | count += sysfs_emit_at(buf, count, "not-defined\n"); |
00ae053a | 46 | else |
64ee2528 | 47 | count += sysfs_emit_at(buf, count, "%lld\n", fps->power); |
00ae053a SP |
48 | |
49 | return count; | |
50 | } | |
51 | ||
f1197343 SP |
52 | static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf) |
53 | { | |
54 | struct acpi_device *acpi_dev = container_of(dev, struct acpi_device, dev); | |
55 | struct acpi_fan_fst fst; | |
56 | int status; | |
57 | ||
58 | status = acpi_fan_get_fst(acpi_dev, &fst); | |
59 | if (status) | |
60 | return status; | |
61 | ||
62 | return sprintf(buf, "%lld\n", fst.speed); | |
63 | } | |
64 | ||
65 | static ssize_t show_fine_grain_control(struct device *dev, struct device_attribute *attr, char *buf) | |
66 | { | |
67 | struct acpi_device *acpi_dev = container_of(dev, struct acpi_device, dev); | |
68 | struct acpi_fan *fan = acpi_driver_data(acpi_dev); | |
69 | ||
70 | return sprintf(buf, "%d\n", fan->fif.fine_grain_ctrl); | |
71 | } | |
72 | ||
00ae053a SP |
73 | int acpi_fan_create_attributes(struct acpi_device *device) |
74 | { | |
75 | struct acpi_fan *fan = acpi_driver_data(device); | |
f1197343 SP |
76 | int i, status; |
77 | ||
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 | ||
87 | /* _FST is present if we are here */ | |
88 | sysfs_attr_init(&fan->fst_speed.attr); | |
89 | fan->fst_speed.show = show_fan_speed; | |
90 | fan->fst_speed.store = NULL; | |
91 | fan->fst_speed.attr.name = "fan_speed_rpm"; | |
92 | fan->fst_speed.attr.mode = 0444; | |
93 | status = sysfs_create_file(&device->dev.kobj, &fan->fst_speed.attr); | |
94 | if (status) | |
95 | goto rem_fine_grain_attr; | |
00ae053a SP |
96 | |
97 | for (i = 0; i < fan->fps_count; ++i) { | |
98 | struct acpi_fan_fps *fps = &fan->fps[i]; | |
99 | ||
100 | snprintf(fps->name, ACPI_FPS_NAME_LEN, "state%d", i); | |
101 | sysfs_attr_init(&fps->dev_attr.attr); | |
102 | fps->dev_attr.show = show_state; | |
103 | fps->dev_attr.store = NULL; | |
104 | fps->dev_attr.attr.name = fps->name; | |
105 | fps->dev_attr.attr.mode = 0444; | |
106 | status = sysfs_create_file(&device->dev.kobj, &fps->dev_attr.attr); | |
107 | if (status) { | |
108 | int j; | |
109 | ||
110 | for (j = 0; j < i; ++j) | |
111 | sysfs_remove_file(&device->dev.kobj, &fan->fps[j].dev_attr.attr); | |
f1197343 | 112 | goto rem_fst_attr; |
00ae053a SP |
113 | } |
114 | } | |
115 | ||
f1197343 SP |
116 | return 0; |
117 | ||
118 | rem_fst_attr: | |
119 | sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr); | |
120 | ||
121 | rem_fine_grain_attr: | |
122 | sysfs_remove_file(&device->dev.kobj, &fan->fine_grain_control.attr); | |
123 | ||
00ae053a SP |
124 | return status; |
125 | } | |
126 | ||
127 | void acpi_fan_delete_attributes(struct acpi_device *device) | |
128 | { | |
129 | struct acpi_fan *fan = acpi_driver_data(device); | |
130 | int i; | |
131 | ||
132 | for (i = 0; i < fan->fps_count; ++i) | |
133 | sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr); | |
f1197343 SP |
134 | |
135 | sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr); | |
136 | sysfs_remove_file(&device->dev.kobj, &fan->fine_grain_control.attr); | |
00ae053a | 137 | } |