Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * acpi_fan.c - ACPI Fan Driver ($Revision: 29 $)
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 : : */
8 : :
9 : : #include <linux/kernel.h>
10 : : #include <linux/module.h>
11 : : #include <linux/init.h>
12 : : #include <linux/types.h>
13 : : #include <linux/uaccess.h>
14 : : #include <linux/thermal.h>
15 : : #include <linux/acpi.h>
16 : : #include <linux/platform_device.h>
17 : : #include <linux/sort.h>
18 : :
19 : : MODULE_AUTHOR("Paul Diefenbaugh");
20 : : MODULE_DESCRIPTION("ACPI Fan Driver");
21 : : MODULE_LICENSE("GPL");
22 : :
23 : : static int acpi_fan_probe(struct platform_device *pdev);
24 : : static int acpi_fan_remove(struct platform_device *pdev);
25 : :
26 : : static const struct acpi_device_id fan_device_ids[] = {
27 : : {"PNP0C0B", 0},
28 : : {"INT1044", 0},
29 : : {"INT3404", 0},
30 : : {"", 0},
31 : : };
32 : : MODULE_DEVICE_TABLE(acpi, fan_device_ids);
33 : :
34 : : #ifdef CONFIG_PM_SLEEP
35 : : static int acpi_fan_suspend(struct device *dev);
36 : : static int acpi_fan_resume(struct device *dev);
37 : : static const struct dev_pm_ops acpi_fan_pm = {
38 : : .resume = acpi_fan_resume,
39 : : .freeze = acpi_fan_suspend,
40 : : .thaw = acpi_fan_resume,
41 : : .restore = acpi_fan_resume,
42 : : };
43 : : #define FAN_PM_OPS_PTR (&acpi_fan_pm)
44 : : #else
45 : : #define FAN_PM_OPS_PTR NULL
46 : : #endif
47 : :
48 : : #define ACPI_FPS_NAME_LEN 20
49 : :
50 : : struct acpi_fan_fps {
51 : : u64 control;
52 : : u64 trip_point;
53 : : u64 speed;
54 : : u64 noise_level;
55 : : u64 power;
56 : : char name[ACPI_FPS_NAME_LEN];
57 : : struct device_attribute dev_attr;
58 : : };
59 : :
60 : : struct acpi_fan_fif {
61 : : u64 revision;
62 : : u64 fine_grain_ctrl;
63 : : u64 step_size;
64 : : u64 low_speed_notification;
65 : : };
66 : :
67 : : struct acpi_fan {
68 : : bool acpi4;
69 : : struct acpi_fan_fif fif;
70 : : struct acpi_fan_fps *fps;
71 : : int fps_count;
72 : : struct thermal_cooling_device *cdev;
73 : : };
74 : :
75 : : static struct platform_driver acpi_fan_driver = {
76 : : .probe = acpi_fan_probe,
77 : : .remove = acpi_fan_remove,
78 : : .driver = {
79 : : .name = "acpi-fan",
80 : : .acpi_match_table = fan_device_ids,
81 : : .pm = FAN_PM_OPS_PTR,
82 : : },
83 : : };
84 : :
85 : : /* thermal cooling device callbacks */
86 : 0 : static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
87 : : *state)
88 : : {
89 : 0 : struct acpi_device *device = cdev->devdata;
90 [ # # ]: 0 : struct acpi_fan *fan = acpi_driver_data(device);
91 : :
92 [ # # ]: 0 : if (fan->acpi4)
93 : 0 : *state = fan->fps_count - 1;
94 : : else
95 : 0 : *state = 1;
96 : 0 : return 0;
97 : : }
98 : :
99 : 0 : static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
100 : : {
101 : 0 : struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
102 : 0 : struct acpi_fan *fan = acpi_driver_data(device);
103 : 0 : union acpi_object *obj;
104 : 0 : acpi_status status;
105 : 0 : int control, i;
106 : :
107 : 0 : status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer);
108 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
109 : 0 : dev_err(&device->dev, "Get fan state failed\n");
110 : 0 : return status;
111 : : }
112 : :
113 : 0 : obj = buffer.pointer;
114 [ # # # # ]: 0 : if (!obj || obj->type != ACPI_TYPE_PACKAGE ||
115 : 0 : obj->package.count != 3 ||
116 [ # # ]: 0 : obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
117 : 0 : dev_err(&device->dev, "Invalid _FST data\n");
118 : 0 : status = -EINVAL;
119 : 0 : goto err;
120 : : }
121 : :
122 : 0 : control = obj->package.elements[1].integer.value;
123 [ # # ]: 0 : for (i = 0; i < fan->fps_count; i++) {
124 : : /*
125 : : * When Fine Grain Control is set, return the state
126 : : * corresponding to maximum fan->fps[i].control
127 : : * value compared to the current speed. Here the
128 : : * fan->fps[] is sorted array with increasing speed.
129 : : */
130 [ # # # # ]: 0 : if (fan->fif.fine_grain_ctrl && control < fan->fps[i].control) {
131 : 0 : i = (i > 0) ? i - 1 : 0;
132 : 0 : break;
133 [ # # ]: 0 : } else if (control == fan->fps[i].control) {
134 : : break;
135 : : }
136 : : }
137 [ # # ]: 0 : if (i == fan->fps_count) {
138 : 0 : dev_dbg(&device->dev, "Invalid control value returned\n");
139 : 0 : status = -EINVAL;
140 : 0 : goto err;
141 : : }
142 : :
143 : 0 : *state = i;
144 : :
145 : 0 : err:
146 : 0 : kfree(obj);
147 : 0 : return status;
148 : : }
149 : :
150 : 0 : static int fan_get_state(struct acpi_device *device, unsigned long *state)
151 : : {
152 : 0 : int result;
153 : 0 : int acpi_state = ACPI_STATE_D0;
154 : :
155 : 0 : result = acpi_device_update_power(device, &acpi_state);
156 [ # # ]: 0 : if (result)
157 : : return result;
158 : :
159 : 0 : *state = acpi_state == ACPI_STATE_D3_COLD
160 : 0 : || acpi_state == ACPI_STATE_D3_HOT ?
161 [ # # # # ]: 0 : 0 : (acpi_state == ACPI_STATE_D0 ? 1 : -1);
162 : 0 : return 0;
163 : : }
164 : :
165 : 0 : static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
166 : : *state)
167 : : {
168 : 0 : struct acpi_device *device = cdev->devdata;
169 [ # # ]: 0 : struct acpi_fan *fan = acpi_driver_data(device);
170 : :
171 [ # # ]: 0 : if (fan->acpi4)
172 : 0 : return fan_get_state_acpi4(device, state);
173 : : else
174 : 0 : return fan_get_state(device, state);
175 : : }
176 : :
177 : 0 : static int fan_set_state(struct acpi_device *device, unsigned long state)
178 : : {
179 : 0 : if (state != 0 && state != 1)
180 : : return -EINVAL;
181 : :
182 [ # # ]: 0 : return acpi_device_set_power(device,
183 : : state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
184 : : }
185 : :
186 : 0 : static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state)
187 : : {
188 [ # # ]: 0 : struct acpi_fan *fan = acpi_driver_data(device);
189 : 0 : acpi_status status;
190 : :
191 [ # # ]: 0 : if (state >= fan->fps_count)
192 : : return -EINVAL;
193 : :
194 : 0 : status = acpi_execute_simple_method(device->handle, "_FSL",
195 : 0 : fan->fps[state].control);
196 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
197 : 0 : dev_dbg(&device->dev, "Failed to set state by _FSL\n");
198 : 0 : return status;
199 : : }
200 : :
201 : : return 0;
202 : : }
203 : :
204 : : static int
205 : 0 : fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
206 : : {
207 : 0 : struct acpi_device *device = cdev->devdata;
208 [ # # ]: 0 : struct acpi_fan *fan = acpi_driver_data(device);
209 : :
210 [ # # ]: 0 : if (fan->acpi4)
211 : 0 : return fan_set_state_acpi4(device, state);
212 : : else
213 [ # # ]: 0 : return fan_set_state(device, state);
214 : : }
215 : :
216 : : static const struct thermal_cooling_device_ops fan_cooling_ops = {
217 : : .get_max_state = fan_get_max_state,
218 : : .get_cur_state = fan_get_cur_state,
219 : : .set_cur_state = fan_set_cur_state,
220 : : };
221 : :
222 : : /* --------------------------------------------------------------------------
223 : : * Driver Interface
224 : : * --------------------------------------------------------------------------
225 : : */
226 : :
227 : : static bool acpi_fan_is_acpi4(struct acpi_device *device)
228 : : {
229 : : return acpi_has_method(device->handle, "_FIF") &&
230 : : acpi_has_method(device->handle, "_FPS") &&
231 : : acpi_has_method(device->handle, "_FSL") &&
232 : : acpi_has_method(device->handle, "_FST");
233 : : }
234 : :
235 : 0 : static int acpi_fan_get_fif(struct acpi_device *device)
236 : : {
237 : 0 : struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
238 : 0 : struct acpi_fan *fan = acpi_driver_data(device);
239 : 0 : struct acpi_buffer format = { sizeof("NNNN"), "NNNN" };
240 : 0 : struct acpi_buffer fif = { sizeof(fan->fif), &fan->fif };
241 : 0 : union acpi_object *obj;
242 : 0 : acpi_status status;
243 : :
244 : 0 : status = acpi_evaluate_object(device->handle, "_FIF", NULL, &buffer);
245 [ # # ]: 0 : if (ACPI_FAILURE(status))
246 : 0 : return status;
247 : :
248 : 0 : obj = buffer.pointer;
249 [ # # # # ]: 0 : if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
250 : 0 : dev_err(&device->dev, "Invalid _FIF data\n");
251 : 0 : status = -EINVAL;
252 : 0 : goto err;
253 : : }
254 : :
255 : 0 : status = acpi_extract_package(obj, &format, &fif);
256 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
257 : 0 : dev_err(&device->dev, "Invalid _FIF element\n");
258 : 0 : status = -EINVAL;
259 : : }
260 : :
261 : 0 : err:
262 : 0 : kfree(obj);
263 : 0 : return status;
264 : : }
265 : :
266 : 0 : static int acpi_fan_speed_cmp(const void *a, const void *b)
267 : : {
268 : 0 : const struct acpi_fan_fps *fps1 = a;
269 : 0 : const struct acpi_fan_fps *fps2 = b;
270 : 0 : return fps1->speed - fps2->speed;
271 : : }
272 : :
273 : 0 : static ssize_t show_state(struct device *dev, struct device_attribute *attr, char *buf)
274 : : {
275 : 0 : struct acpi_fan_fps *fps = container_of(attr, struct acpi_fan_fps, dev_attr);
276 : 0 : int count;
277 : :
278 [ # # ]: 0 : if (fps->control == 0xFFFFFFFF || fps->control > 100)
279 : 0 : count = snprintf(buf, PAGE_SIZE, "not-defined:");
280 : : else
281 : 0 : count = snprintf(buf, PAGE_SIZE, "%lld:", fps->control);
282 : :
283 [ # # ]: 0 : if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)
284 : 0 : count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
285 : : else
286 : 0 : count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->trip_point);
287 : :
288 [ # # ]: 0 : if (fps->speed == 0xFFFFFFFF)
289 : 0 : count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
290 : : else
291 : 0 : count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->speed);
292 : :
293 [ # # ]: 0 : if (fps->noise_level == 0xFFFFFFFF)
294 : 0 : count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
295 : : else
296 : 0 : count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->noise_level * 100);
297 : :
298 [ # # ]: 0 : if (fps->power == 0xFFFFFFFF)
299 : 0 : count += snprintf(&buf[count], PAGE_SIZE, "not-defined\n");
300 : : else
301 : 0 : count += snprintf(&buf[count], PAGE_SIZE, "%lld\n", fps->power);
302 : :
303 : 0 : return count;
304 : : }
305 : :
306 : 0 : static int acpi_fan_get_fps(struct acpi_device *device)
307 : : {
308 : 0 : struct acpi_fan *fan = acpi_driver_data(device);
309 : 0 : struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
310 : 0 : union acpi_object *obj;
311 : 0 : acpi_status status;
312 : 0 : int i;
313 : :
314 : 0 : status = acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer);
315 [ # # ]: 0 : if (ACPI_FAILURE(status))
316 : 0 : return status;
317 : :
318 : 0 : obj = buffer.pointer;
319 [ # # # # : 0 : if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
# # ]
320 : 0 : dev_err(&device->dev, "Invalid _FPS data\n");
321 : 0 : status = -EINVAL;
322 : 0 : goto err;
323 : : }
324 : :
325 : 0 : fan->fps_count = obj->package.count - 1; /* minus revision field */
326 [ # # ]: 0 : fan->fps = devm_kcalloc(&device->dev,
327 : : fan->fps_count, sizeof(struct acpi_fan_fps),
328 : : GFP_KERNEL);
329 [ # # ]: 0 : if (!fan->fps) {
330 : 0 : dev_err(&device->dev, "Not enough memory\n");
331 : 0 : status = -ENOMEM;
332 : 0 : goto err;
333 : : }
334 [ # # ]: 0 : for (i = 0; i < fan->fps_count; i++) {
335 : 0 : struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
336 : 0 : struct acpi_buffer fps = { offsetof(struct acpi_fan_fps, name),
337 : 0 : &fan->fps[i] };
338 : 0 : status = acpi_extract_package(&obj->package.elements[i + 1],
339 : : &format, &fps);
340 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
341 : 0 : dev_err(&device->dev, "Invalid _FPS element\n");
342 : 0 : goto err;
343 : : }
344 : : }
345 : :
346 : : /* sort the state array according to fan speed in increase order */
347 : 0 : sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
348 : : acpi_fan_speed_cmp, NULL);
349 : :
350 [ # # ]: 0 : for (i = 0; i < fan->fps_count; ++i) {
351 : 0 : struct acpi_fan_fps *fps = &fan->fps[i];
352 : :
353 : 0 : snprintf(fps->name, ACPI_FPS_NAME_LEN, "state%d", i);
354 : 0 : fps->dev_attr.show = show_state;
355 : 0 : fps->dev_attr.store = NULL;
356 : 0 : fps->dev_attr.attr.name = fps->name;
357 : 0 : fps->dev_attr.attr.mode = 0444;
358 : 0 : status = sysfs_create_file(&device->dev.kobj, &fps->dev_attr.attr);
359 [ # # ]: 0 : if (status) {
360 : : int j;
361 : :
362 [ # # ]: 0 : for (j = 0; j < i; ++j)
363 : 0 : sysfs_remove_file(&device->dev.kobj, &fan->fps[j].dev_attr.attr);
364 : : break;
365 : : }
366 : : }
367 : :
368 : 0 : err:
369 : 0 : kfree(obj);
370 : 0 : return status;
371 : : }
372 : :
373 : 0 : static int acpi_fan_probe(struct platform_device *pdev)
374 : : {
375 : 0 : int result = 0;
376 : 0 : struct thermal_cooling_device *cdev;
377 : 0 : struct acpi_fan *fan;
378 [ # # ]: 0 : struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
379 : 0 : char *name;
380 : :
381 : 0 : fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
382 [ # # ]: 0 : if (!fan) {
383 : 0 : dev_err(&device->dev, "No memory for fan\n");
384 : 0 : return -ENOMEM;
385 : : }
386 : 0 : device->driver_data = fan;
387 : 0 : platform_set_drvdata(pdev, fan);
388 : :
389 [ # # ]: 0 : if (acpi_fan_is_acpi4(device)) {
390 : 0 : result = acpi_fan_get_fif(device);
391 [ # # ]: 0 : if (result)
392 : : return result;
393 : :
394 : 0 : result = acpi_fan_get_fps(device);
395 [ # # ]: 0 : if (result)
396 : : return result;
397 : :
398 : 0 : fan->acpi4 = true;
399 : : } else {
400 : 0 : result = acpi_device_update_power(device, NULL);
401 [ # # ]: 0 : if (result) {
402 : 0 : dev_err(&device->dev, "Failed to set initial power state\n");
403 : 0 : goto err_end;
404 : : }
405 : : }
406 : :
407 [ # # ]: 0 : if (!strncmp(pdev->name, "PNP0C0B", strlen("PNP0C0B")))
408 : : name = "Fan";
409 : : else
410 : 0 : name = acpi_device_bid(device);
411 : :
412 : 0 : cdev = thermal_cooling_device_register(name, device,
413 : : &fan_cooling_ops);
414 [ # # ]: 0 : if (IS_ERR(cdev)) {
415 : 0 : result = PTR_ERR(cdev);
416 : 0 : goto err_end;
417 : : }
418 : :
419 : 0 : dev_dbg(&pdev->dev, "registered as cooling_device%d\n", cdev->id);
420 : :
421 : 0 : fan->cdev = cdev;
422 : 0 : result = sysfs_create_link(&pdev->dev.kobj,
423 : : &cdev->device.kobj,
424 : : "thermal_cooling");
425 [ # # ]: 0 : if (result)
426 : 0 : dev_err(&pdev->dev, "Failed to create sysfs link 'thermal_cooling'\n");
427 : :
428 : 0 : result = sysfs_create_link(&cdev->device.kobj,
429 : : &pdev->dev.kobj,
430 : : "device");
431 [ # # ]: 0 : if (result) {
432 : 0 : dev_err(&pdev->dev, "Failed to create sysfs link 'device'\n");
433 : 0 : goto err_end;
434 : : }
435 : :
436 : : return 0;
437 : :
438 : 0 : err_end:
439 [ # # ]: 0 : if (fan->acpi4) {
440 : : int i;
441 : :
442 [ # # ]: 0 : for (i = 0; i < fan->fps_count; ++i)
443 : 0 : sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
444 : : }
445 : :
446 : : return result;
447 : : }
448 : :
449 : 0 : static int acpi_fan_remove(struct platform_device *pdev)
450 : : {
451 [ # # ]: 0 : struct acpi_fan *fan = platform_get_drvdata(pdev);
452 : :
453 [ # # ]: 0 : if (fan->acpi4) {
454 [ # # ]: 0 : struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
455 : 0 : int i;
456 : :
457 [ # # ]: 0 : for (i = 0; i < fan->fps_count; ++i)
458 : 0 : sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
459 : : }
460 : 0 : sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
461 : 0 : sysfs_remove_link(&fan->cdev->device.kobj, "device");
462 : 0 : thermal_cooling_device_unregister(fan->cdev);
463 : :
464 : 0 : return 0;
465 : : }
466 : :
467 : : #ifdef CONFIG_PM_SLEEP
468 : 0 : static int acpi_fan_suspend(struct device *dev)
469 : : {
470 [ # # ]: 0 : struct acpi_fan *fan = dev_get_drvdata(dev);
471 [ # # ]: 0 : if (fan->acpi4)
472 : : return 0;
473 : :
474 [ # # ]: 0 : acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D0);
475 : :
476 : 0 : return AE_OK;
477 : : }
478 : :
479 : 0 : static int acpi_fan_resume(struct device *dev)
480 : : {
481 : 0 : int result;
482 [ # # ]: 0 : struct acpi_fan *fan = dev_get_drvdata(dev);
483 : :
484 [ # # ]: 0 : if (fan->acpi4)
485 : : return 0;
486 : :
487 [ # # ]: 0 : result = acpi_device_update_power(ACPI_COMPANION(dev), NULL);
488 [ # # ]: 0 : if (result)
489 : 0 : dev_err(dev, "Error updating fan power state\n");
490 : :
491 : : return result;
492 : : }
493 : : #endif
494 : :
495 : 28 : module_platform_driver(acpi_fan_driver);
|