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