Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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