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

thermal: add hwmon sysfs I/F

Add hwmon sys I/F for generic thermal driver.

Note: we have one hwmon class device for EACH TYPE of the thermal zone device.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Acked-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Len Brown <len.brown@intel.com>

authored by

Zhang Rui and committed by
Len Brown
e68b16ab 9ec732ff

+187
+163
drivers/thermal/thermal.c
··· 295 295 296 296 /* Device management */ 297 297 298 + #if defined(CONFIG_HWMON) || \ 299 + (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE)) 300 + /* hwmon sys I/F */ 301 + #include <linux/hwmon.h> 302 + static LIST_HEAD(thermal_hwmon_list); 303 + 304 + static ssize_t 305 + name_show(struct device *dev, struct device_attribute *attr, char *buf) 306 + { 307 + struct thermal_hwmon_device *hwmon = dev->driver_data; 308 + return sprintf(buf, "%s\n", hwmon->type); 309 + } 310 + static DEVICE_ATTR(name, 0444, name_show, NULL); 311 + 312 + static ssize_t 313 + temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) 314 + { 315 + struct thermal_hwmon_attr *hwmon_attr 316 + = container_of(attr, struct thermal_hwmon_attr, attr); 317 + struct thermal_zone_device *tz 318 + = container_of(hwmon_attr, struct thermal_zone_device, 319 + temp_input); 320 + 321 + return tz->ops->get_temp(tz, buf); 322 + } 323 + 324 + static ssize_t 325 + temp_crit_show(struct device *dev, struct device_attribute *attr, 326 + char *buf) 327 + { 328 + struct thermal_hwmon_attr *hwmon_attr 329 + = container_of(attr, struct thermal_hwmon_attr, attr); 330 + struct thermal_zone_device *tz 331 + = container_of(hwmon_attr, struct thermal_zone_device, 332 + temp_crit); 333 + 334 + return tz->ops->get_trip_temp(tz, 0, buf); 335 + } 336 + 337 + 338 + static int 339 + thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) 340 + { 341 + struct thermal_hwmon_device *hwmon; 342 + int new_hwmon_device = 1; 343 + int result; 344 + 345 + mutex_lock(&thermal_list_lock); 346 + list_for_each_entry(hwmon, &thermal_hwmon_list, node) 347 + if (!strcmp(hwmon->type, tz->type)) { 348 + new_hwmon_device = 0; 349 + mutex_unlock(&thermal_list_lock); 350 + goto register_sys_interface; 351 + } 352 + mutex_unlock(&thermal_list_lock); 353 + 354 + hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL); 355 + if (!hwmon) 356 + return -ENOMEM; 357 + 358 + INIT_LIST_HEAD(&hwmon->tz_list); 359 + strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH); 360 + hwmon->device = hwmon_device_register(NULL); 361 + if (IS_ERR(hwmon->device)) { 362 + result = PTR_ERR(hwmon->device); 363 + goto free_mem; 364 + } 365 + hwmon->device->driver_data = hwmon; 366 + result = device_create_file(hwmon->device, &dev_attr_name); 367 + if (result) 368 + goto unregister_hwmon_device; 369 + 370 + register_sys_interface: 371 + tz->hwmon = hwmon; 372 + hwmon->count++; 373 + 374 + snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH, 375 + "temp%d_input", hwmon->count); 376 + tz->temp_input.attr.attr.name = tz->temp_input.name; 377 + tz->temp_input.attr.attr.mode = 0444; 378 + tz->temp_input.attr.show = temp_input_show; 379 + result = device_create_file(hwmon->device, &tz->temp_input.attr); 380 + if (result) 381 + goto unregister_hwmon_device; 382 + 383 + if (tz->ops->get_crit_temp) { 384 + unsigned long temperature; 385 + if (!tz->ops->get_crit_temp(tz, &temperature)) { 386 + snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH, 387 + "temp%d_crit", hwmon->count); 388 + tz->temp_crit.attr.attr.name = tz->temp_crit.name; 389 + tz->temp_crit.attr.attr.mode = 0444; 390 + tz->temp_crit.attr.show = temp_crit_show; 391 + result = device_create_file(hwmon->device, 392 + &tz->temp_crit.attr); 393 + if (result) 394 + goto unregister_hwmon_device; 395 + } 396 + } 397 + 398 + mutex_lock(&thermal_list_lock); 399 + if (new_hwmon_device) 400 + list_add_tail(&hwmon->node, &thermal_hwmon_list); 401 + list_add_tail(&tz->hwmon_node, &hwmon->tz_list); 402 + mutex_unlock(&thermal_list_lock); 403 + 404 + return 0; 405 + 406 + unregister_hwmon_device: 407 + device_remove_file(hwmon->device, &tz->temp_crit.attr); 408 + device_remove_file(hwmon->device, &tz->temp_input.attr); 409 + if (new_hwmon_device) { 410 + device_remove_file(hwmon->device, &dev_attr_name); 411 + hwmon_device_unregister(hwmon->device); 412 + } 413 + free_mem: 414 + if (new_hwmon_device) 415 + kfree(hwmon); 416 + 417 + return result; 418 + } 419 + 420 + static void 421 + thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) 422 + { 423 + struct thermal_hwmon_device *hwmon = tz->hwmon; 424 + 425 + tz->hwmon = NULL; 426 + device_remove_file(hwmon->device, &tz->temp_input.attr); 427 + device_remove_file(hwmon->device, &tz->temp_crit.attr); 428 + 429 + mutex_lock(&thermal_list_lock); 430 + list_del(&tz->hwmon_node); 431 + if (!list_empty(&hwmon->tz_list)) { 432 + mutex_unlock(&thermal_list_lock); 433 + return; 434 + } 435 + list_del(&hwmon->node); 436 + mutex_unlock(&thermal_list_lock); 437 + 438 + device_remove_file(hwmon->device, &dev_attr_name); 439 + hwmon_device_unregister(hwmon->device); 440 + kfree(hwmon); 441 + } 442 + #else 443 + static int 444 + thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) 445 + { 446 + return 0; 447 + } 448 + 449 + static void 450 + thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) 451 + { 452 + } 453 + #endif 454 + 455 + 298 456 /** 299 457 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone 300 458 * @tz: thermal zone device ··· 800 642 goto unregister; 801 643 } 802 644 645 + result = thermal_add_hwmon_sysfs(tz); 646 + if (result) 647 + goto unregister; 648 + 803 649 mutex_lock(&thermal_list_lock); 804 650 list_add_tail(&tz->node, &thermal_tz_list); 805 651 if (ops->bind) ··· 862 700 for (count = 0; count < tz->trips; count++) 863 701 TRIP_POINT_ATTR_REMOVE(&tz->device, count); 864 702 703 + thermal_remove_hwmon_sysfs(tz); 865 704 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); 866 705 idr_destroy(&tz->idr); 867 706 mutex_destroy(&tz->lock);
+24
include/linux/thermal.h
··· 66 66 ((long)t-2732+5)/10 : ((long)t-2732-5)/10) 67 67 #define CELSIUS_TO_KELVIN(t) ((t)*10+2732) 68 68 69 + #if defined(CONFIG_HWMON) || \ 70 + (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE)) 71 + /* thermal zone devices with the same type share one hwmon device */ 72 + struct thermal_hwmon_device { 73 + char type[THERMAL_NAME_LENGTH]; 74 + struct device *device; 75 + int count; 76 + struct list_head tz_list; 77 + struct list_head node; 78 + }; 79 + 80 + struct thermal_hwmon_attr { 81 + struct device_attribute attr; 82 + char name[16]; 83 + }; 84 + #endif 85 + 69 86 struct thermal_zone_device { 70 87 int id; 71 88 char type[THERMAL_NAME_LENGTH]; ··· 94 77 struct idr idr; 95 78 struct mutex lock; /* protect cooling devices list */ 96 79 struct list_head node; 80 + #if defined(CONFIG_HWMON) || \ 81 + (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE)) 82 + struct list_head hwmon_node; 83 + struct thermal_hwmon_device *hwmon; 84 + struct thermal_hwmon_attr temp_input; /* hwmon sys attr */ 85 + struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */ 86 + #endif 97 87 }; 98 88 99 89 struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,