summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJinyoung Park <jinyoungp@nvidia.com>2013-03-21 03:44:38 -0400
committerNicolin Chen <nicolinc@nvidia.com>2017-08-14 21:38:52 -0400
commit211c09b5d97072bea1e282bdd0ca236f8fbdee5b (patch)
treedd6e9252ec7cd3a3ca47be9e31147666b6258891
parenta80e0e397671343e1900eb265dbd281998f0bb3a (diff)
drivers: misc: therm_est: Add multiple trip points support
Replaced cdev_typa and trip_temp to struct thermal_trip_info to support multiple trip points on therm_est. And the struct thermal_trip_info has hysteresis for trip temp. So applied hysteresis to trip temp. Bug 1233363 Bug 1236444 Signed-off-by: Jinyoung Park <jinyoungp@nvidia.com> Reviewed-on: http://git-master/r/211123 (cherry picked from commit d832906d904916a263c831d1bf55031070818991) Change-Id: I6ce2806a323c25ec298291d1e4ee067c3adaebfa Signed-off-by: Jinyoung Park <jinyoungp@nvidia.com> Reviewed-on: http://git-master/r/215542
-rw-r--r--drivers/misc/therm_est.c183
-rw-r--r--include/linux/therm_est.h13
2 files changed, 142 insertions, 54 deletions
diff --git a/drivers/misc/therm_est.c b/drivers/misc/therm_est.c
index ab543bb7d..ef3399acf 100644
--- a/drivers/misc/therm_est.c
+++ b/drivers/misc/therm_est.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * drivers/misc/therm_est.c 2 * drivers/misc/therm_est.c
3 * 3 *
4 * Copyright (c) 2010-2013 NVIDIA Corporation. All rights reserved. 4 * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved.
5 * 5 *
6 * This software is licensed under the terms of the GNU General Public 6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and 7 * License version 2, as published by the Free Software Foundation, and
@@ -34,32 +34,73 @@
34#include <linux/suspend.h> 34#include <linux/suspend.h>
35 35
36struct therm_estimator { 36struct therm_estimator {
37 long cur_temp; 37 struct thermal_zone_device *thz;
38 long polling_period; 38 int num_trips;
39 struct thermal_trip_info *trips;
40 struct thermal_zone_params *tzp;
41
39 struct workqueue_struct *workqueue; 42 struct workqueue_struct *workqueue;
40 struct delayed_work therm_est_work; 43 struct delayed_work therm_est_work;
41 long toffset; 44 long cur_temp;
45 long low_limit;
46 long high_limit;
42 int ntemp; 47 int ntemp;
43 int ndevs; 48 long toffset;
44 struct therm_est_subdevice *devs; 49 long polling_period;
45 struct thermal_zone_device *thz;
46 char *cdev_type;
47 long trip_temp;
48 int tc1; 50 int tc1;
49 int tc2; 51 int tc2;
52 int ndevs;
53 struct therm_est_subdevice *devs;
54
50#ifdef CONFIG_PM 55#ifdef CONFIG_PM
51 struct notifier_block pm_nb; 56 struct notifier_block pm_nb;
52#endif 57#endif
53}; 58};
54 59
60static void therm_est_update_limits(struct therm_estimator *est)
61{
62 const int MAX_HIGH_TEMP = 128000;
63 long low_temp = 0, high_temp = MAX_HIGH_TEMP;
64 long trip_temp, passive_low_temp = MAX_HIGH_TEMP;
65 enum thermal_trip_type trip_type;
66 struct thermal_trip_info *trip_state;
67 int i;
68
69 for (i = 0; i < est->num_trips; i++) {
70 trip_state = &est->trips[i];
71 est->thz->ops->get_trip_temp(est->thz, i, &trip_temp);
72 est->thz->ops->get_trip_type(est->thz, i, &trip_type);
73
74 if (!trip_state->tripped) { /* not tripped? update high */
75 if (trip_temp < high_temp)
76 high_temp = trip_temp;
77 } else { /* tripped? update low */
78 if (trip_type != THERMAL_TRIP_PASSIVE) {
79 /* get highest ACTIVE */
80 if (trip_temp > low_temp)
81 low_temp = trip_temp;
82 } else {
83 /* get lowest PASSIVE */
84 if (trip_temp < passive_low_temp)
85 passive_low_temp = trip_temp;
86 }
87 }
88 }
89
90 if (passive_low_temp != MAX_HIGH_TEMP)
91 low_temp = max(low_temp, passive_low_temp);
92
93 est->low_limit = low_temp;
94 est->high_limit = high_temp;
95}
96
55static void therm_est_work_func(struct work_struct *work) 97static void therm_est_work_func(struct work_struct *work)
56{ 98{
57 int i, j, index, sum = 0; 99 int i, j, index, sum = 0;
58 long temp; 100 long temp;
59 struct delayed_work *dwork = container_of (work, 101 struct delayed_work *dwork = container_of(work,
60 struct delayed_work, work); 102 struct delayed_work, work);
61 struct therm_estimator *est = container_of( 103 struct therm_estimator *est = container_of(dwork,
62 dwork,
63 struct therm_estimator, 104 struct therm_estimator,
64 therm_est_work); 105 therm_est_work);
65 106
@@ -78,12 +119,13 @@ static void therm_est_work_func(struct work_struct *work)
78 } 119 }
79 120
80 est->cur_temp = sum / 100 + est->toffset; 121 est->cur_temp = sum / 100 + est->toffset;
81
82 est->ntemp++; 122 est->ntemp++;
83 123
84 if (est->cur_temp >= est->trip_temp) 124 if (est->thz && ((est->cur_temp < est->low_limit) ||
85 if (est->thz && !est->thz->passive) 125 (est->cur_temp >= est->high_limit))) {
86 thermal_zone_device_update(est->thz); 126 thermal_zone_device_update(est->thz);
127 therm_est_update_limits(est);
128 }
87 129
88 queue_delayed_work(est->workqueue, &est->therm_est_work, 130 queue_delayed_work(est->workqueue, &est->therm_est_work,
89 msecs_to_jiffies(est->polling_period)); 131 msecs_to_jiffies(est->polling_period));
@@ -93,10 +135,18 @@ static int therm_est_bind(struct thermal_zone_device *thz,
93 struct thermal_cooling_device *cdev) 135 struct thermal_cooling_device *cdev)
94{ 136{
95 struct therm_estimator *est = thz->devdata; 137 struct therm_estimator *est = thz->devdata;
138 struct thermal_trip_info *trip_state;
139 int i;
96 140
97 if (!strcmp(cdev->type, est->cdev_type)) 141 for (i = 0; i < est->num_trips; i++) {
98 thermal_zone_bind_cooling_device(thz, 0, cdev, 142 trip_state = &est->trips[i];
99 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT); 143 if (trip_state->cdev_type &&
144 !strncmp(trip_state->cdev_type, cdev->type,
145 THERMAL_NAME_LENGTH))
146 thermal_zone_bind_cooling_device(thz, i, cdev,
147 trip_state->upper,
148 trip_state->lower);
149 }
100 150
101 return 0; 151 return 0;
102} 152}
@@ -105,40 +155,59 @@ static int therm_est_unbind(struct thermal_zone_device *thz,
105 struct thermal_cooling_device *cdev) 155 struct thermal_cooling_device *cdev)
106{ 156{
107 struct therm_estimator *est = thz->devdata; 157 struct therm_estimator *est = thz->devdata;
158 struct thermal_trip_info *trip_state;
159 int i;
108 160
109 if (!strcmp(cdev->type, est->cdev_type)) 161 for (i = 0; i < est->num_trips; i++) {
110 thermal_zone_unbind_cooling_device(thz, 0, cdev); 162 trip_state = &est->trips[i];
163 if (trip_state->cdev_type &&
164 !strncmp(trip_state->cdev_type, cdev->type,
165 THERMAL_NAME_LENGTH))
166 thermal_zone_unbind_cooling_device(thz, i, cdev);
167 }
111 168
112 return 0; 169 return 0;
113} 170}
114 171
115static int therm_est_get_trip_type(struct thermal_zone_device *thz, 172static int therm_est_get_trip_type(struct thermal_zone_device *thz,
116 int trip, 173 int trip, enum thermal_trip_type *type)
117 enum thermal_trip_type *type)
118{ 174{
119 *type = THERMAL_TRIP_PASSIVE; 175 struct therm_estimator *est = thz->devdata;
176
177 *type = est->trips[trip].trip_type;
120 return 0; 178 return 0;
121} 179}
122 180
123static int therm_est_get_trip_temp(struct thermal_zone_device *thz, 181static int therm_est_get_trip_temp(struct thermal_zone_device *thz,
124 int trip, 182 int trip, unsigned long *temp)
125 unsigned long *temp)
126{ 183{
127 struct therm_estimator *est = thz->devdata; 184 struct therm_estimator *est = thz->devdata;
185 struct thermal_trip_info *trip_state = &est->trips[trip];
186 unsigned long trip_temp, zone_temp;
187
188 trip_temp = trip_state->trip_temp;
189 zone_temp = thz->temperature;
190
191 if (zone_temp >= trip_temp) {
192 trip_temp -= trip_state->hysteresis;
193 trip_state->tripped = true;
194 } else if (trip_state->tripped) {
195 trip_temp -= trip_state->hysteresis;
196 if (zone_temp < trip_temp)
197 trip_state->tripped = false;
198 }
128 199
129 *temp = est->trip_temp; 200 *temp = trip_temp;
130 201
131 return 0; 202 return 0;
132} 203}
133 204
134static int therm_est_set_trip_temp(struct thermal_zone_device *thz, 205static int therm_est_set_trip_temp(struct thermal_zone_device *thz,
135 int trip, 206 int trip, unsigned long temp)
136 unsigned long temp)
137{ 207{
138 struct therm_estimator *est = thz->devdata; 208 struct therm_estimator *est = thz->devdata;
139 209
140 est->trip_temp = temp; 210 est->trips[trip].trip_temp = temp;
141
142 return 0; 211 return 0;
143} 212}
144 213
@@ -146,29 +215,42 @@ static int therm_est_get_temp(struct thermal_zone_device *thz,
146 unsigned long *temp) 215 unsigned long *temp)
147{ 216{
148 struct therm_estimator *est = thz->devdata; 217 struct therm_estimator *est = thz->devdata;
218
149 *temp = est->cur_temp; 219 *temp = est->cur_temp;
150 return 0; 220 return 0;
151} 221}
152 222
153static int therm_est_get_trend(struct thermal_zone_device *thz, 223static int therm_est_get_trend(struct thermal_zone_device *thz,
154 int trip, 224 int trip, enum thermal_trend *trend)
155 enum thermal_trend *trend)
156{ 225{
157 struct therm_estimator *est = thz->devdata; 226 struct therm_estimator *est = thz->devdata;
227 struct thermal_trip_info *trip_state = &est->trips[trip];
228 long trip_temp;
158 int new_trend; 229 int new_trend;
159 int cur_temp; 230 int cur_temp;
160 231
232 thz->ops->get_trip_temp(thz, trip, &trip_temp);
233
161 cur_temp = thz->temperature; 234 cur_temp = thz->temperature;
162 new_trend = (est->tc1 * (cur_temp - thz->last_temperature)) + 235 new_trend = (est->tc1 * (cur_temp - thz->last_temperature)) +
163 (est->tc2 * (cur_temp - est->trip_temp)); 236 (est->tc2 * (cur_temp - trip_temp));
164 237
165 if (new_trend > 0) 238 switch (trip_state->trip_type) {
239 case THERMAL_TRIP_ACTIVE:
240 /* aggressive active cooling */
166 *trend = THERMAL_TREND_RAISING; 241 *trend = THERMAL_TREND_RAISING;
167 else if (new_trend < 0) 242 break;
168 *trend = THERMAL_TREND_DROPPING; 243 case THERMAL_TRIP_PASSIVE:
169 else 244 if (new_trend > 0)
170 *trend = THERMAL_TREND_STABLE; 245 *trend = THERMAL_TREND_RAISING;
171 246 else if (new_trend < 0)
247 *trend = THERMAL_TREND_DROPPING;
248 else
249 *trend = THERMAL_TREND_STABLE;
250 break;
251 default:
252 return -EINVAL;
253 }
172 return 0; 254 return 0;
173} 255}
174 256
@@ -390,6 +472,8 @@ static int therm_est_pm_notify(struct notifier_block *nb,
390 cancel_delayed_work_sync(&est->therm_est_work); 472 cancel_delayed_work_sync(&est->therm_est_work);
391 break; 473 break;
392 case PM_POST_SUSPEND: 474 case PM_POST_SUSPEND:
475 est->low_limit = 0;
476 est->high_limit = 0;
393 therm_est_init_history(est); 477 therm_est_init_history(est);
394 queue_delayed_work(est->workqueue, 478 queue_delayed_work(est->workqueue,
395 &est->therm_est_work, 479 &est->therm_est_work,
@@ -436,17 +520,18 @@ static int __devinit therm_est_probe(struct platform_device *pdev)
436 &est->therm_est_work, 520 &est->therm_est_work,
437 msecs_to_jiffies(est->polling_period)); 521 msecs_to_jiffies(est->polling_period));
438 522
439 est->trip_temp = data->trip_temp; 523 est->num_trips = data->num_trips;
440 est->cdev_type = data->cdev_type; 524 est->trips = data->trips;
525 est->tzp = data->tzp;
441 526
442 est->thz = thermal_zone_device_register(dev_name(&pdev->dev), 527 est->thz = thermal_zone_device_register(dev_name(&pdev->dev),
443 1, 528 est->num_trips,
444 0x1, 529 (1 << est->num_trips) - 1,
445 est, 530 est,
446 &therm_est_ops, 531 &therm_est_ops,
447 NULL, 532 est->tzp,
448 data->passive_delay, 533 data->passive_delay,
449 0); 534 0);
450 if (IS_ERR_OR_NULL(est->thz)) 535 if (IS_ERR_OR_NULL(est->thz))
451 goto err; 536 goto err;
452 537
diff --git a/include/linux/therm_est.h b/include/linux/therm_est.h
index 8877108af..f1ccbf0de 100644
--- a/include/linux/therm_est.h
+++ b/include/linux/therm_est.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * include/linux/therm_est.h 2 * include/linux/therm_est.h
3 * 3 *
4 * Copyright (c) 2010-2012, NVIDIA Corporation. 4 * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved.
5 * 5 *
6 * This software is licensed under the terms of the GNU General Public 6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and 7 * License version 2, as published by the Free Software Foundation, and
@@ -18,6 +18,8 @@
18#define _LINUX_THERM_EST_H 18#define _LINUX_THERM_EST_H
19 19
20#include <linux/workqueue.h> 20#include <linux/workqueue.h>
21#include <linux/thermal.h>
22#include <linux/platform_data/thermal_sensors.h>
21 23
22#define HIST_LEN (20) 24#define HIST_LEN (20)
23 25
@@ -31,17 +33,18 @@ struct therm_est_subdevice {
31}; 33};
32 34
33struct therm_est_data { 35struct therm_est_data {
34 /* trip point info : there's only 1 trip point */ 36 /* trip point info */
35 char *cdev_type; /* cooling device for this trip */ 37 int num_trips;
36 long trip_temp; 38 struct thermal_trip_info *trips;
37 39
38 /* zone parameters */ 40 /* zone parameters */
41 struct thermal_zone_params *tzp;
39 long toffset; 42 long toffset;
40 long polling_period; 43 long polling_period;
41 int passive_delay; 44 int passive_delay;
42 int ndevs;
43 int tc1; 45 int tc1;
44 int tc2; 46 int tc2;
47 int ndevs;
45 struct therm_est_subdevice devs[]; 48 struct therm_est_subdevice devs[];
46}; 49};
47 50