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