0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0014
0015 #include <linux/device.h>
0016 #include <linux/err.h>
0017 #include <linux/export.h>
0018 #include <linux/slab.h>
0019 #include <linux/string.h>
0020 #include <linux/sysfs.h>
0021
0022 #include <trace/events/thermal.h>
0023
0024 #include "thermal_core.h"
0025
0026 int get_tz_trend(struct thermal_zone_device *tz, int trip)
0027 {
0028 enum thermal_trend trend;
0029
0030 if (tz->emul_temperature || !tz->ops->get_trend ||
0031 tz->ops->get_trend(tz, trip, &trend)) {
0032 if (tz->temperature > tz->last_temperature)
0033 trend = THERMAL_TREND_RAISING;
0034 else if (tz->temperature < tz->last_temperature)
0035 trend = THERMAL_TREND_DROPPING;
0036 else
0037 trend = THERMAL_TREND_STABLE;
0038 }
0039
0040 return trend;
0041 }
0042
0043 struct thermal_instance *
0044 get_thermal_instance(struct thermal_zone_device *tz,
0045 struct thermal_cooling_device *cdev, int trip)
0046 {
0047 struct thermal_instance *pos = NULL;
0048 struct thermal_instance *target_instance = NULL;
0049
0050 mutex_lock(&tz->lock);
0051 mutex_lock(&cdev->lock);
0052
0053 list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
0054 if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
0055 target_instance = pos;
0056 break;
0057 }
0058 }
0059
0060 mutex_unlock(&cdev->lock);
0061 mutex_unlock(&tz->lock);
0062
0063 return target_instance;
0064 }
0065 EXPORT_SYMBOL(get_thermal_instance);
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077 int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
0078 {
0079 int ret = -EINVAL;
0080 int count;
0081 int crit_temp = INT_MAX;
0082 enum thermal_trip_type type;
0083
0084 if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
0085 goto exit;
0086
0087 mutex_lock(&tz->lock);
0088
0089 ret = tz->ops->get_temp(tz, temp);
0090
0091 if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {
0092 for (count = 0; count < tz->num_trips; count++) {
0093 ret = tz->ops->get_trip_type(tz, count, &type);
0094 if (!ret && type == THERMAL_TRIP_CRITICAL) {
0095 ret = tz->ops->get_trip_temp(tz, count,
0096 &crit_temp);
0097 break;
0098 }
0099 }
0100
0101
0102
0103
0104
0105
0106 if (!ret && *temp < crit_temp)
0107 *temp = tz->emul_temperature;
0108 }
0109
0110 mutex_unlock(&tz->lock);
0111 exit:
0112 return ret;
0113 }
0114 EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128 void thermal_zone_set_trips(struct thermal_zone_device *tz)
0129 {
0130 int low = -INT_MAX;
0131 int high = INT_MAX;
0132 int trip_temp, hysteresis;
0133 int i, ret;
0134
0135 mutex_lock(&tz->lock);
0136
0137 if (!tz->ops->set_trips || !tz->ops->get_trip_hyst)
0138 goto exit;
0139
0140 for (i = 0; i < tz->num_trips; i++) {
0141 int trip_low;
0142
0143 tz->ops->get_trip_temp(tz, i, &trip_temp);
0144 tz->ops->get_trip_hyst(tz, i, &hysteresis);
0145
0146 trip_low = trip_temp - hysteresis;
0147
0148 if (trip_low < tz->temperature && trip_low > low)
0149 low = trip_low;
0150
0151 if (trip_temp > tz->temperature && trip_temp < high)
0152 high = trip_temp;
0153 }
0154
0155
0156 if (tz->prev_low_trip == low && tz->prev_high_trip == high)
0157 goto exit;
0158
0159 tz->prev_low_trip = low;
0160 tz->prev_high_trip = high;
0161
0162 dev_dbg(&tz->device,
0163 "new temperature boundaries: %d < x < %d\n", low, high);
0164
0165
0166
0167
0168
0169 ret = tz->ops->set_trips(tz, low, high);
0170 if (ret)
0171 dev_err(&tz->device, "Failed to set trips: %d\n", ret);
0172
0173 exit:
0174 mutex_unlock(&tz->lock);
0175 }
0176
0177 static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev,
0178 int target)
0179 {
0180 if (cdev->ops->set_cur_state(cdev, target))
0181 return;
0182
0183 thermal_notify_cdev_state_update(cdev->id, target);
0184 thermal_cooling_device_stats_update(cdev, target);
0185 }
0186
0187 void __thermal_cdev_update(struct thermal_cooling_device *cdev)
0188 {
0189 struct thermal_instance *instance;
0190 unsigned long target = 0;
0191
0192
0193 list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
0194 dev_dbg(&cdev->device, "zone%d->target=%lu\n",
0195 instance->tz->id, instance->target);
0196 if (instance->target == THERMAL_NO_TARGET)
0197 continue;
0198 if (instance->target > target)
0199 target = instance->target;
0200 }
0201
0202 thermal_cdev_set_cur_state(cdev, target);
0203
0204 trace_cdev_update(cdev, target);
0205 dev_dbg(&cdev->device, "set to state %lu\n", target);
0206 }
0207
0208
0209
0210
0211
0212
0213
0214 void thermal_cdev_update(struct thermal_cooling_device *cdev)
0215 {
0216 mutex_lock(&cdev->lock);
0217 if (!cdev->updated) {
0218 __thermal_cdev_update(cdev);
0219 cdev->updated = true;
0220 }
0221 mutex_unlock(&cdev->lock);
0222 }
0223
0224
0225
0226
0227
0228
0229
0230
0231 int thermal_zone_get_slope(struct thermal_zone_device *tz)
0232 {
0233 if (tz && tz->tzp)
0234 return tz->tzp->slope;
0235 return 1;
0236 }
0237 EXPORT_SYMBOL_GPL(thermal_zone_get_slope);
0238
0239
0240
0241
0242
0243
0244
0245
0246 int thermal_zone_get_offset(struct thermal_zone_device *tz)
0247 {
0248 if (tz && tz->tzp)
0249 return tz->tzp->offset;
0250 return 0;
0251 }
0252 EXPORT_SYMBOL_GPL(thermal_zone_get_offset);