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

thermal: sysfs: Add a new sysfs node emul_temp for thermal emulation

This patch adds support to set the emulated temperature method in
thermal zone (sensor). After setting this feature thermal zone may
report this temperature and not the actual temperature. The emulation
implementation may be based on sensor capability through platform
specific handler or pure software emulation if no platform handler defined.

This is useful in debugging different temperature threshold and its
associated cooling action. Critical threshold's cannot be emulated.
Writing 0 on this node should disable emulation.

Signed-off-by: Amit Daniel Kachhap <amit.daniel@samsung.com>
Acked-by: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>

authored by

Amit Daniel Kachhap and committed by
Zhang Rui
e6e238c3 c8165dc0

+91 -11
+13
Documentation/thermal/sysfs-api.txt
··· 55 55 .get_trip_type: get the type of certain trip point. 56 56 .get_trip_temp: get the temperature above which the certain trip point 57 57 will be fired. 58 + .set_emul_temp: set the emulation temperature which helps in debugging 59 + different threshold temperature points. 58 60 59 61 1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz) 60 62 ··· 155 153 |---trip_point_[0-*]_temp: Trip point temperature 156 154 |---trip_point_[0-*]_type: Trip point type 157 155 |---trip_point_[0-*]_hyst: Hysteresis value for this trip point 156 + |---emul_temp: Emulated temperature set node 158 157 159 158 Thermal cooling device sys I/F, created once it's registered: 160 159 /sys/class/thermal/cooling_device[0-*]: ··· 254 251 Unit: millidegrees Celsius 255 252 Valid values: 0 (disabled) or greater than 1000 256 253 RW, Optional 254 + 255 + emul_temp 256 + Interface to set the emulated temperature method in thermal zone 257 + (sensor). After setting this temperature, the thermal zone may pass 258 + this temperature to platform emulation function if registered or 259 + cache it locally. This is useful in debugging different temperature 260 + threshold and its associated cooling action. This is write only node 261 + and writing 0 on this node should disable emulation. 262 + Unit: millidegree Celsius 263 + WO, Optional 257 264 258 265 ***************************** 259 266 * Cooling device attributes *
+8
drivers/thermal/Kconfig
··· 78 78 and not the ACPI interface. 79 79 If you want this support, you should say Y here. 80 80 81 + config THERMAL_EMULATION 82 + bool "Thermal emulation mode support" 83 + help 84 + Enable this option to make a emul_temp sysfs node in thermal zone 85 + directory to support temperature emulation. With emulation sysfs node, 86 + user can manually input temperature and test the different trip 87 + threshold behaviour for simulation purpose. 88 + 81 89 config SPEAR_THERMAL 82 90 bool "SPEAr thermal sensor driver" 83 91 depends on PLAT_SPEAR
+68 -11
drivers/thermal/thermal_sys.c
··· 378 378 monitor_thermal_zone(tz); 379 379 } 380 380 381 + static int thermal_zone_get_temp(struct thermal_zone_device *tz, 382 + unsigned long *temp) 383 + { 384 + int ret = 0, count; 385 + unsigned long crit_temp = -1UL; 386 + enum thermal_trip_type type; 387 + 388 + mutex_lock(&tz->lock); 389 + 390 + ret = tz->ops->get_temp(tz, temp); 391 + #ifdef CONFIG_THERMAL_EMULATION 392 + if (!tz->emul_temperature) 393 + goto skip_emul; 394 + 395 + for (count = 0; count < tz->trips; count++) { 396 + ret = tz->ops->get_trip_type(tz, count, &type); 397 + if (!ret && type == THERMAL_TRIP_CRITICAL) { 398 + ret = tz->ops->get_trip_temp(tz, count, &crit_temp); 399 + break; 400 + } 401 + } 402 + 403 + if (ret) 404 + goto skip_emul; 405 + 406 + if (*temp < crit_temp) 407 + *temp = tz->emul_temperature; 408 + skip_emul: 409 + #endif 410 + mutex_unlock(&tz->lock); 411 + return ret; 412 + } 413 + 381 414 static void update_temperature(struct thermal_zone_device *tz) 382 415 { 383 416 long temp; 384 417 int ret; 385 418 386 - mutex_lock(&tz->lock); 387 - 388 - ret = tz->ops->get_temp(tz, &temp); 419 + ret = thermal_zone_get_temp(tz, &temp); 389 420 if (ret) { 390 421 dev_warn(&tz->device, "failed to read out thermal zone %d\n", 391 422 tz->id); 392 - goto exit; 423 + return; 393 424 } 394 425 426 + mutex_lock(&tz->lock); 395 427 tz->last_temperature = tz->temperature; 396 428 tz->temperature = temp; 397 - 398 - exit: 399 429 mutex_unlock(&tz->lock); 400 430 } 401 431 ··· 468 438 long temperature; 469 439 int ret; 470 440 471 - if (!tz->ops->get_temp) 472 - return -EPERM; 473 - 474 - ret = tz->ops->get_temp(tz, &temperature); 441 + ret = thermal_zone_get_temp(tz, &temperature); 475 442 476 443 if (ret) 477 444 return ret; ··· 728 701 return sprintf(buf, "%s\n", tz->governor->name); 729 702 } 730 703 704 + #ifdef CONFIG_THERMAL_EMULATION 705 + static ssize_t 706 + emul_temp_store(struct device *dev, struct device_attribute *attr, 707 + const char *buf, size_t count) 708 + { 709 + struct thermal_zone_device *tz = to_thermal_zone(dev); 710 + int ret = 0; 711 + unsigned long temperature; 712 + 713 + if (kstrtoul(buf, 10, &temperature)) 714 + return -EINVAL; 715 + 716 + if (!tz->ops->set_emul_temp) { 717 + mutex_lock(&tz->lock); 718 + tz->emul_temperature = temperature; 719 + mutex_unlock(&tz->lock); 720 + } else { 721 + ret = tz->ops->set_emul_temp(tz, temperature); 722 + } 723 + 724 + return ret ? ret : count; 725 + } 726 + static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store); 727 + #endif/*CONFIG_THERMAL_EMULATION*/ 728 + 731 729 static DEVICE_ATTR(type, 0444, type_show, NULL); 732 730 static DEVICE_ATTR(temp, 0444, temp_show, NULL); 733 731 static DEVICE_ATTR(mode, 0644, mode_show, mode_store); ··· 895 843 temp_input); 896 844 struct thermal_zone_device *tz = temp->tz; 897 845 898 - ret = tz->ops->get_temp(tz, &temperature); 846 + ret = thermal_zone_get_temp(tz, &temperature); 899 847 900 848 if (ret) 901 849 return ret; ··· 1648 1596 goto unregister; 1649 1597 } 1650 1598 1599 + #ifdef CONFIG_THERMAL_EMULATION 1600 + result = device_create_file(&tz->device, &dev_attr_emul_temp); 1601 + if (result) 1602 + goto unregister; 1603 + #endif 1651 1604 /* Create policy attribute */ 1652 1605 result = device_create_file(&tz->device, &dev_attr_policy); 1653 1606 if (result)
+2
include/linux/thermal.h
··· 123 123 int (*set_trip_hyst) (struct thermal_zone_device *, int, 124 124 unsigned long); 125 125 int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *); 126 + int (*set_emul_temp) (struct thermal_zone_device *, unsigned long); 126 127 int (*get_trend) (struct thermal_zone_device *, int, 127 128 enum thermal_trend *); 128 129 int (*notify) (struct thermal_zone_device *, int, ··· 166 165 int polling_delay; 167 166 int temperature; 168 167 int last_temperature; 168 + int emul_temperature; 169 169 int passive; 170 170 unsigned int forced_passive; 171 171 const struct thermal_zone_device_ops *ops;