diff options
author | Amit Daniel Kachhap <amit.daniel@samsung.com> | 2013-02-03 19:30:15 -0500 |
---|---|---|
committer | Zhang Rui <rui.zhang@intel.com> | 2013-02-06 00:45:42 -0500 |
commit | e6e238c38bd4d42d5e2cddb2165e1a46e0fb1200 (patch) | |
tree | f09a49a963463468a39a62908583d5b0484c9d99 /drivers/thermal | |
parent | c8165dc0ea75855b0bff6e5edbe4957b8a63d021 (diff) |
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>
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/Kconfig | 8 | ||||
-rw-r--r-- | drivers/thermal/thermal_sys.c | 79 |
2 files changed, 76 insertions, 11 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index faf38c522fa8..e4cf7fbc3a59 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
@@ -78,6 +78,14 @@ config CPU_THERMAL | |||
78 | and not the ACPI interface. | 78 | and not the ACPI interface. |
79 | If you want this support, you should say Y here. | 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 | config SPEAR_THERMAL | 89 | config SPEAR_THERMAL |
82 | bool "SPEAr thermal sensor driver" | 90 | bool "SPEAr thermal sensor driver" |
83 | depends on PLAT_SPEAR | 91 | depends on PLAT_SPEAR |
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 0a1bf6b032ea..0675687c6de8 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c | |||
@@ -378,24 +378,54 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) | |||
378 | monitor_thermal_zone(tz); | 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 | static void update_temperature(struct thermal_zone_device *tz) | 414 | static void update_temperature(struct thermal_zone_device *tz) |
382 | { | 415 | { |
383 | long temp; | 416 | long temp; |
384 | int ret; | 417 | int ret; |
385 | 418 | ||
386 | mutex_lock(&tz->lock); | 419 | ret = thermal_zone_get_temp(tz, &temp); |
387 | |||
388 | ret = tz->ops->get_temp(tz, &temp); | ||
389 | if (ret) { | 420 | if (ret) { |
390 | dev_warn(&tz->device, "failed to read out thermal zone %d\n", | 421 | dev_warn(&tz->device, "failed to read out thermal zone %d\n", |
391 | tz->id); | 422 | tz->id); |
392 | goto exit; | 423 | return; |
393 | } | 424 | } |
394 | 425 | ||
426 | mutex_lock(&tz->lock); | ||
395 | tz->last_temperature = tz->temperature; | 427 | tz->last_temperature = tz->temperature; |
396 | tz->temperature = temp; | 428 | tz->temperature = temp; |
397 | |||
398 | exit: | ||
399 | mutex_unlock(&tz->lock); | 429 | mutex_unlock(&tz->lock); |
400 | } | 430 | } |
401 | 431 | ||
@@ -438,10 +468,7 @@ temp_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
438 | long temperature; | 468 | long temperature; |
439 | int ret; | 469 | int ret; |
440 | 470 | ||
441 | if (!tz->ops->get_temp) | 471 | ret = thermal_zone_get_temp(tz, &temperature); |
442 | return -EPERM; | ||
443 | |||
444 | ret = tz->ops->get_temp(tz, &temperature); | ||
445 | 472 | ||
446 | if (ret) | 473 | if (ret) |
447 | return ret; | 474 | return ret; |
@@ -701,6 +728,31 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf) | |||
701 | return sprintf(buf, "%s\n", tz->governor->name); | 728 | return sprintf(buf, "%s\n", tz->governor->name); |
702 | } | 729 | } |
703 | 730 | ||
731 | #ifdef CONFIG_THERMAL_EMULATION | ||
732 | static ssize_t | ||
733 | emul_temp_store(struct device *dev, struct device_attribute *attr, | ||
734 | const char *buf, size_t count) | ||
735 | { | ||
736 | struct thermal_zone_device *tz = to_thermal_zone(dev); | ||
737 | int ret = 0; | ||
738 | unsigned long temperature; | ||
739 | |||
740 | if (kstrtoul(buf, 10, &temperature)) | ||
741 | return -EINVAL; | ||
742 | |||
743 | if (!tz->ops->set_emul_temp) { | ||
744 | mutex_lock(&tz->lock); | ||
745 | tz->emul_temperature = temperature; | ||
746 | mutex_unlock(&tz->lock); | ||
747 | } else { | ||
748 | ret = tz->ops->set_emul_temp(tz, temperature); | ||
749 | } | ||
750 | |||
751 | return ret ? ret : count; | ||
752 | } | ||
753 | static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store); | ||
754 | #endif/*CONFIG_THERMAL_EMULATION*/ | ||
755 | |||
704 | static DEVICE_ATTR(type, 0444, type_show, NULL); | 756 | static DEVICE_ATTR(type, 0444, type_show, NULL); |
705 | static DEVICE_ATTR(temp, 0444, temp_show, NULL); | 757 | static DEVICE_ATTR(temp, 0444, temp_show, NULL); |
706 | static DEVICE_ATTR(mode, 0644, mode_show, mode_store); | 758 | static DEVICE_ATTR(mode, 0644, mode_show, mode_store); |
@@ -843,7 +895,7 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
843 | temp_input); | 895 | temp_input); |
844 | struct thermal_zone_device *tz = temp->tz; | 896 | struct thermal_zone_device *tz = temp->tz; |
845 | 897 | ||
846 | ret = tz->ops->get_temp(tz, &temperature); | 898 | ret = thermal_zone_get_temp(tz, &temperature); |
847 | 899 | ||
848 | if (ret) | 900 | if (ret) |
849 | return ret; | 901 | return ret; |
@@ -1596,6 +1648,11 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, | |||
1596 | goto unregister; | 1648 | goto unregister; |
1597 | } | 1649 | } |
1598 | 1650 | ||
1651 | #ifdef CONFIG_THERMAL_EMULATION | ||
1652 | result = device_create_file(&tz->device, &dev_attr_emul_temp); | ||
1653 | if (result) | ||
1654 | goto unregister; | ||
1655 | #endif | ||
1599 | /* Create policy attribute */ | 1656 | /* Create policy attribute */ |
1600 | result = device_create_file(&tz->device, &dev_attr_policy); | 1657 | result = device_create_file(&tz->device, &dev_attr_policy); |
1601 | if (result) | 1658 | if (result) |