aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/thermal_sys.c188
1 files changed, 186 insertions, 2 deletions
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index bd139adc6d32..6378741882f3 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -30,6 +30,7 @@
30#include <linux/idr.h> 30#include <linux/idr.h>
31#include <linux/thermal.h> 31#include <linux/thermal.h>
32#include <linux/spinlock.h> 32#include <linux/spinlock.h>
33#include <linux/reboot.h>
33 34
34MODULE_AUTHOR("Zhang Rui"); 35MODULE_AUTHOR("Zhang Rui");
35MODULE_DESCRIPTION("Generic thermal management sysfs support"); 36MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -517,6 +518,97 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
517} 518}
518#endif 519#endif
519 520
521static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
522 int delay)
523{
524 cancel_delayed_work(&(tz->poll_queue));
525
526 if (!delay)
527 return;
528
529 if (delay > 1000)
530 schedule_delayed_work(&(tz->poll_queue),
531 round_jiffies(msecs_to_jiffies(delay)));
532 else
533 schedule_delayed_work(&(tz->poll_queue),
534 msecs_to_jiffies(delay));
535}
536
537static void thermal_zone_device_passive(struct thermal_zone_device *tz,
538 int temp, int trip_temp, int trip)
539{
540 int trend = 0;
541 struct thermal_cooling_device_instance *instance;
542 struct thermal_cooling_device *cdev;
543 long state, max_state;
544
545 /*
546 * Above Trip?
547 * -----------
548 * Calculate the thermal trend (using the passive cooling equation)
549 * and modify the performance limit for all passive cooling devices
550 * accordingly. Note that we assume symmetry.
551 */
552 if (temp >= trip_temp) {
553 tz->passive = true;
554
555 trend = (tz->tc1 * (temp - tz->last_temperature)) +
556 (tz->tc2 * (temp - trip_temp));
557
558 /* Heating up? */
559 if (trend > 0) {
560 list_for_each_entry(instance, &tz->cooling_devices,
561 node) {
562 if (instance->trip != trip)
563 continue;
564 cdev = instance->cdev;
565 cdev->ops->get_cur_state(cdev, &state);
566 cdev->ops->get_max_state(cdev, &max_state);
567 if (state++ < max_state)
568 cdev->ops->set_cur_state(cdev, state);
569 }
570 } else if (trend < 0) { /* Cooling off? */
571 list_for_each_entry(instance, &tz->cooling_devices,
572 node) {
573 if (instance->trip != trip)
574 continue;
575 cdev = instance->cdev;
576 cdev->ops->get_cur_state(cdev, &state);
577 cdev->ops->get_max_state(cdev, &max_state);
578 if (state > 0)
579 cdev->ops->set_cur_state(cdev, --state);
580 }
581 }
582 return;
583 }
584
585 /*
586 * Below Trip?
587 * -----------
588 * Implement passive cooling hysteresis to slowly increase performance
589 * and avoid thrashing around the passive trip point. Note that we
590 * assume symmetry.
591 */
592 list_for_each_entry(instance, &tz->cooling_devices, node) {
593 if (instance->trip != trip)
594 continue;
595 cdev = instance->cdev;
596 cdev->ops->get_cur_state(cdev, &state);
597 cdev->ops->get_max_state(cdev, &max_state);
598 if (state > 0)
599 cdev->ops->set_cur_state(cdev, --state);
600 if (state == 0)
601 tz->passive = false;
602 }
603}
604
605static void thermal_zone_device_check(struct work_struct *work)
606{
607 struct thermal_zone_device *tz = container_of(work, struct
608 thermal_zone_device,
609 poll_queue.work);
610 thermal_zone_device_update(tz);
611}
520 612
521/** 613/**
522 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone 614 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
@@ -787,20 +879,101 @@ void thermal_cooling_device_unregister(struct
787EXPORT_SYMBOL(thermal_cooling_device_unregister); 879EXPORT_SYMBOL(thermal_cooling_device_unregister);
788 880
789/** 881/**
882 * thermal_zone_device_update - force an update of a thermal zone's state
883 * @ttz: the thermal zone to update
884 */
885
886void thermal_zone_device_update(struct thermal_zone_device *tz)
887{
888 int count, ret = 0;
889 long temp, trip_temp;
890 enum thermal_trip_type trip_type;
891 struct thermal_cooling_device_instance *instance;
892 struct thermal_cooling_device *cdev;
893
894 mutex_lock(&tz->lock);
895
896 tz->ops->get_temp(tz, &temp);
897
898 for (count = 0; count < tz->trips; count++) {
899 tz->ops->get_trip_type(tz, count, &trip_type);
900 tz->ops->get_trip_temp(tz, count, &trip_temp);
901
902 switch (trip_type) {
903 case THERMAL_TRIP_CRITICAL:
904 if (temp > trip_temp) {
905 if (tz->ops->notify)
906 ret = tz->ops->notify(tz, count,
907 trip_type);
908 if (!ret) {
909 printk(KERN_EMERG
910 "Critical temperature reached (%ld C), shutting down.\n",
911 temp/1000);
912 orderly_poweroff(true);
913 }
914 }
915 break;
916 case THERMAL_TRIP_HOT:
917 if (temp > trip_temp)
918 if (tz->ops->notify)
919 tz->ops->notify(tz, count, trip_type);
920 break;
921 case THERMAL_TRIP_ACTIVE:
922 list_for_each_entry(instance, &tz->cooling_devices,
923 node) {
924 if (instance->trip != count)
925 continue;
926
927 cdev = instance->cdev;
928
929 if (temp > trip_temp)
930 cdev->ops->set_cur_state(cdev, 1);
931 else
932 cdev->ops->set_cur_state(cdev, 0);
933 }
934 break;
935 case THERMAL_TRIP_PASSIVE:
936 if (temp > trip_temp || tz->passive)
937 thermal_zone_device_passive(tz, temp,
938 trip_temp, count);
939 break;
940 }
941 }
942 tz->last_temperature = temp;
943 if (tz->passive)
944 thermal_zone_device_set_polling(tz, tz->passive_delay);
945 else if (tz->polling_delay)
946 thermal_zone_device_set_polling(tz, tz->polling_delay);
947 mutex_unlock(&tz->lock);
948}
949EXPORT_SYMBOL(thermal_zone_device_update);
950
951/**
790 * thermal_zone_device_register - register a new thermal zone device 952 * thermal_zone_device_register - register a new thermal zone device
791 * @type: the thermal zone device type 953 * @type: the thermal zone device type
792 * @trips: the number of trip points the thermal zone support 954 * @trips: the number of trip points the thermal zone support
793 * @devdata: private device data 955 * @devdata: private device data
794 * @ops: standard thermal zone device callbacks 956 * @ops: standard thermal zone device callbacks
957 * @tc1: thermal coefficient 1 for passive calculations
958 * @tc2: thermal coefficient 2 for passive calculations
959 * @passive_delay: number of milliseconds to wait between polls when
960 * performing passive cooling
961 * @polling_delay: number of milliseconds to wait between polls when checking
962 * whether trip points have been crossed (0 for interrupt
963 * driven systems)
795 * 964 *
796 * thermal_zone_device_unregister() must be called when the device is no 965 * thermal_zone_device_unregister() must be called when the device is no
797 * longer needed. 966 * longer needed. The passive cooling formula uses tc1 and tc2 as described in
967 * section 11.1.5.1 of the ACPI specification 3.0.
798 */ 968 */
799struct thermal_zone_device *thermal_zone_device_register(char *type, 969struct thermal_zone_device *thermal_zone_device_register(char *type,
800 int trips, 970 int trips,
801 void *devdata, struct 971 void *devdata, struct
802 thermal_zone_device_ops 972 thermal_zone_device_ops
803 *ops) 973 *ops, int tc1, int
974 tc2,
975 int passive_delay,
976 int polling_delay)
804{ 977{
805 struct thermal_zone_device *tz; 978 struct thermal_zone_device *tz;
806 struct thermal_cooling_device *pos; 979 struct thermal_cooling_device *pos;
@@ -834,6 +1007,11 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
834 tz->device.class = &thermal_class; 1007 tz->device.class = &thermal_class;
835 tz->devdata = devdata; 1008 tz->devdata = devdata;
836 tz->trips = trips; 1009 tz->trips = trips;
1010 tz->tc1 = tc1;
1011 tz->tc2 = tc2;
1012 tz->passive_delay = passive_delay;
1013 tz->polling_delay = polling_delay;
1014
837 dev_set_name(&tz->device, "thermal_zone%d", tz->id); 1015 dev_set_name(&tz->device, "thermal_zone%d", tz->id);
838 result = device_register(&tz->device); 1016 result = device_register(&tz->device);
839 if (result) { 1017 if (result) {
@@ -879,6 +1057,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
879 } 1057 }
880 mutex_unlock(&thermal_list_lock); 1058 mutex_unlock(&thermal_list_lock);
881 1059
1060 INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
1061
1062 thermal_zone_device_update(tz);
1063
882 if (!result) 1064 if (!result)
883 return tz; 1065 return tz;
884 1066
@@ -918,6 +1100,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
918 tz->ops->unbind(tz, cdev); 1100 tz->ops->unbind(tz, cdev);
919 mutex_unlock(&thermal_list_lock); 1101 mutex_unlock(&thermal_list_lock);
920 1102
1103 thermal_zone_device_set_polling(tz, 0);
1104
921 if (tz->type[0]) 1105 if (tz->type[0])
922 device_remove_file(&tz->device, &dev_attr_type); 1106 device_remove_file(&tz->device, &dev_attr_type);
923 device_remove_file(&tz->device, &dev_attr_temp); 1107 device_remove_file(&tz->device, &dev_attr_temp);