summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHyungwoo Yang <hyungwooy@nvidia.com>2014-11-25 18:08:54 -0500
committerNicolin Chen <nicolinc@nvidia.com>2017-08-14 21:38:52 -0400
commitdd6e683e308d39fc697cd58e854fdcd13100e57c (patch)
tree82c79fce645c34a21c81baeb8efa5abfbabf38a6
parent303ebe41f25ac9f2e1aa1c5d1c6d0ac76d59adbd (diff)
tegra: therm_est: support multiple sets of coefficients
Edit original commit to use 'thermal_zone_of_device_ops'. enable multlple sets of coefficients. Bug 1582735 (cherry-picked from commit If0c31037fdf1d8004c9ee241e0387ceef1bb022f) Signed-off-by: Hyungwoo Yang <hyungwooy@nvidia.com> Reviewed-on: http://git-master/r/655573 Change-Id: If8ec11e80238f70227d473891076a04a8cd1301d Signed-off-by: Srikar Srimath Tirumala <srikars@nvidia.com>
-rw-r--r--Documentation/devicetree/bindings/misc/therm_est.txt46
-rw-r--r--drivers/misc/therm_est.c356
-rw-r--r--include/linux/therm_est.h24
3 files changed, 288 insertions, 138 deletions
diff --git a/Documentation/devicetree/bindings/misc/therm_est.txt b/Documentation/devicetree/bindings/misc/therm_est.txt
index b0532c721..0dbcb147a 100644
--- a/Documentation/devicetree/bindings/misc/therm_est.txt
+++ b/Documentation/devicetree/bindings/misc/therm_est.txt
@@ -2,34 +2,46 @@ Thermal estimator driver.
2 2
3Properties : 3Properties :
4 - compatible : Should contain "nvidia,therm-est". 4 - compatible : Should contain "nvidia,therm-est".
5 - toffset : Temperature offset for thermal estimation, in milli-celsius.
6 - polling-period : Polling wait times for thermal estimation, in milliseconds. 5 - polling-period : Polling wait times for thermal estimation, in milliseconds.
7 - tc1 : Coefficient 1 for thermal trend calculation. 6 - tc1 : Coefficient 1 for thermal trend calculation.
8 - tc2 : Coefficient 2 for thermal trend calculation. 7 - tc2 : Coefficient 2 for thermal trend calculation.
9 - node for subdev : Node for subdevice information. Required. 8 - node for subdev : Node for subdevice information. Required.
10 This node can be numerous.
11 9
12Properties in subdevice node : Required. Can be numerous. 10Properties in subdev node : Required.
13 - device_type : Should contain "therm-est-subdev". 11 - subdev_names : list of strings. It contains list of the name of the therm
14 - dev_data : Thermal zone device type for thermal estimation. 12 zones used for estimation.
15 - coeffs : An array of coefficients, the number of entries should be twenty. 13 - node for coeff_set : contains a set of zone specific coefficients+offset.
14 This node can be numerous.
15
16Properties in coeff_set : Required. Can be numerous.
17 - toffset : Temperature offset for thermal estimation, in milli-celsius.
18 - coeffs : An array of coefficients, the number of entries should be twenty
19 per sub device.
16 20
17Example: 21Example:
18 22
19 therm_est { 23 therm_est_sensor {
20 device_type = "therm-est-subdev"; 24 device_type = "therm-est-subdev";
21 toffset = <0>;
22 polling-period = <1100>; 25 polling-period = <1100>;
23 tc1 = <10>; 26 tc1 = <10>;
24 tc2 = <1>; 27 tc2 = <1>;
25 subdevs@0 { 28 subdev {
26 compatible = "nvidia,therm-est-subdev"; 29 subdev_names = "Tdiode_tegra", "Tboard_tegra";
27 dev-data = "nct_ext"; 30
28 coeffs = "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; 31 coeff_set@0 {
29 }; 32 toffset = <9793>;
30 subdevs@1 { 33 coeffs = <
31 compatible = "nvidia,therm-est-subdev"; 34 2 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 (-1) (-7)
32 dev-data = "nct_int"; 35 (-11) (-7) (-5) (-3) (-3) (-2) (-1) 0 0 0 1 1 1 2 2 3 4 6 11 18
33 coeffs = "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; 36 >;
37 };
38
39 coeff_set@1 {
40 toffset = <708>;
41 coeffs = <
42 -1 -1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 (-1) (-3) (-9)
43 (-6) (-4) (-1) 0 0 0 0 0 0 0 1 1 1 2 2 5 7 10 17 20
44 >;
45 };
34 }; 46 };
35 }; 47 };
diff --git a/drivers/misc/therm_est.c b/drivers/misc/therm_est.c
index 32ddd7fac..156fab120 100644
--- a/drivers/misc/therm_est.c
+++ b/drivers/misc/therm_est.c
@@ -44,14 +44,11 @@ struct therm_estimator {
44 long cur_temp; 44 long cur_temp;
45 long low_limit; 45 long low_limit;
46 long high_limit; 46 long high_limit;
47 int ntemp;
48 long toffset;
49 long polling_period; 47 long polling_period;
50 int polling_enabled; 48 int polling_enabled;
51 int tc1; 49 int tc1;
52 int tc2; 50 int tc2;
53 int ndevs; 51 struct therm_est_subdevice *subdevice;
54 struct therm_est_subdevice *devs;
55 bool *tripped_info; 52 bool *tripped_info;
56 53
57 int use_activator; 54 int use_activator;
@@ -123,30 +120,37 @@ static void therm_est_update_limits(struct therm_estimator *est)
123 120
124static void therm_est_work_func(struct work_struct *work) 121static void therm_est_work_func(struct work_struct *work)
125{ 122{
126 int i, j, index, sum = 0;
127 long temp;
128 struct delayed_work *dwork = container_of(work, 123 struct delayed_work *dwork = container_of(work,
129 struct delayed_work, work); 124 struct delayed_work, work);
130 struct therm_estimator *est = container_of(dwork, 125 struct therm_estimator *est = container_of(dwork,
131 struct therm_estimator, 126 struct therm_estimator,
132 therm_est_work); 127 therm_est_work);
128 struct therm_est_subdevice *subdevice;
129 struct therm_est_coeffs *coeffs_set;
130 long *thz_coeffs, *hist;
131 long temp;
132 int i, j, index, sum = 0;
133 133
134 for (i = 0; i < est->ndevs; i++) { 134 subdevice = est->subdevice;
135 if (therm_est_subdev_get_temp(est->devs[i].sub_thz, &temp)) 135 coeffs_set = &subdevice->coeffs_set[subdevice->active_coeffs];
136
137 subdevice->ntemp = (subdevice->ntemp + 1) % HIST_LEN;
138 for (i = 0; i < subdevice->num_devs; i++) {
139 if (therm_est_subdev_get_temp(subdevice->sub_thz[i].thz, &temp))
136 continue; 140 continue;
137 est->devs[i].hist[(est->ntemp % HIST_LEN)] = temp; 141 subdevice->sub_thz[i].hist[subdevice->ntemp] = temp;
138 } 142 }
139 143
140 for (i = 0; i < est->ndevs; i++) { 144 for (i = 0; i < subdevice->num_devs; i++) {
145 hist = subdevice->sub_thz[i].hist;
146 thz_coeffs = coeffs_set->coeffs[i];
141 for (j = 0; j < HIST_LEN; j++) { 147 for (j = 0; j < HIST_LEN; j++) {
142 index = (est->ntemp - j + HIST_LEN) % HIST_LEN; 148 index = (subdevice->ntemp - j + HIST_LEN) % HIST_LEN;
143 sum += est->devs[i].hist[index] * 149 sum += hist[index] * thz_coeffs[j];
144 est->devs[i].coeffs[j];
145 } 150 }
146 } 151 }
147 152
148 est->cur_temp = sum / 100 + est->toffset; 153 est->cur_temp = sum / 100 + coeffs_set->toffset;
149 est->ntemp++;
150 154
151 if (est->thz && ((est->cur_temp < est->low_limit) || 155 if (est->thz && ((est->cur_temp < est->low_limit) ||
152 (est->cur_temp >= est->high_limit))) { 156 (est->cur_temp >= est->high_limit))) {
@@ -194,18 +198,17 @@ static int therm_est_trip_update(void *of_data, int trip)
194 198
195static int therm_est_init_history(struct therm_estimator *est) 199static int therm_est_init_history(struct therm_estimator *est)
196{ 200{
197 int i, j; 201 struct therm_est_sub_thz *sub_thz;
198 struct therm_est_subdevice *dev;
199 long temp; 202 long temp;
203 int i, j;
200 204
201 for (i = 0; i < est->ndevs; i++) { 205 sub_thz = est->subdevice->sub_thz;
202 dev = &est->devs[i]; 206 for (i = 0; i < est->subdevice->num_devs; i++) {
203 207 if (therm_est_subdev_get_temp(sub_thz[i].thz, &temp))
204 if (therm_est_subdev_get_temp(dev->sub_thz, &temp))
205 return -EINVAL; 208 return -EINVAL;
206 209
207 for (j = 0; j < HIST_LEN; j++) 210 for (j = 0; j < HIST_LEN; j++)
208 dev->hist[j] = temp; 211 sub_thz[i].hist[j] = temp;
209 } 212 }
210 213
211 return 0; 214 return 0;
@@ -230,25 +233,57 @@ static int therm_est_polling(struct therm_estimator *est,
230 return 0; 233 return 0;
231} 234}
232 235
236static int switch_active_coeffs(struct therm_estimator *est, int active_coeffs)
237{
238 struct therm_est_subdevice *subdevice = est->subdevice;
239
240 if (active_coeffs < 0 || active_coeffs >= subdevice->num_coeffs)
241 return -EINVAL;
242
243 subdevice->active_coeffs = active_coeffs;
244
245 return 0;
246}
247
233static ssize_t show_coeff(struct device *dev, 248static ssize_t show_coeff(struct device *dev,
234 struct device_attribute *da, 249 struct device_attribute *da,
235 char *buf) 250 char *buf)
236{ 251{
237 struct therm_estimator *est = dev_get_drvdata(dev); 252 struct therm_estimator *est = dev_get_drvdata(dev);
238 ssize_t len, total_len = 0; 253 struct therm_est_subdevice *subdevice = est->subdevice;
239 int i, j; 254 struct therm_est_coeffs *coeffs_set;
240 for (i = 0; i < est->ndevs; i++) { 255 long *coeffs;
241 len = snprintf(buf + total_len, 256 ssize_t total_len = 0;
242 PAGE_SIZE - total_len, "[%d]", i); 257 int i, j, k;
243 total_len += len; 258
244 for (j = 0; j < HIST_LEN; j++) { 259 total_len += snprintf(buf + total_len, PAGE_SIZE - total_len,
245 len = snprintf(buf + total_len, 260 "Total %02d set(s) are available\n\n",
246 PAGE_SIZE - total_len, " %ld", 261 subdevice->num_coeffs);
247 est->devs[i].coeffs[j]); 262
248 total_len += len; 263 for (i = 0; i < subdevice->num_coeffs; i++) {
264 total_len += snprintf(buf + total_len, PAGE_SIZE - total_len,
265 "- SET %02d - %s\n", i,
266 (i == subdevice->active_coeffs)?"active":"");
267
268 coeffs_set = subdevice->coeffs_set + i;
269 for (j = 0; j < subdevice->num_devs; j++) {
270 total_len += snprintf(buf + total_len,
271 PAGE_SIZE - total_len,
272 "%s : ",
273 subdevice->sub_thz[j].thz->type);
274 coeffs = coeffs_set->coeffs[j];
275 for (k = 0; k < HIST_LEN; k++) {
276 total_len += snprintf(buf + total_len,
277 PAGE_SIZE - total_len, " %ld",
278 coeffs[k]);
279 }
280 total_len += snprintf(buf + total_len,
281 PAGE_SIZE - total_len, "\n");
249 } 282 }
250 len = snprintf(buf + total_len, PAGE_SIZE - total_len, "\n"); 283 total_len += snprintf(buf + total_len,
251 total_len += len; 284 PAGE_SIZE - total_len,
285 "toffset : %ld\n\n",
286 coeffs_set->toffset);
252 } 287 }
253 return strlen(buf); 288 return strlen(buf);
254} 289}
@@ -258,15 +293,15 @@ static ssize_t set_coeff(struct device *dev,
258 const char *buf, size_t count) 293 const char *buf, size_t count)
259{ 294{
260 struct therm_estimator *est = dev_get_drvdata(dev); 295 struct therm_estimator *est = dev_get_drvdata(dev);
261 int devid, scount; 296 int coeffs_index, dev_index, scount;
262 long coeff[20]; 297 long coeff[20];
263 298
264 if (HIST_LEN > 20) 299 if (HIST_LEN > 20)
265 return -EINVAL; 300 return -EINVAL;
266 301
267 scount = sscanf(buf, "[%d] %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld " \ 302 scount = sscanf(buf, "[%d][%d] %ld %ld %ld %ld %ld %ld %ld %ld %ld " \
268 "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", 303 "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
269 &devid, 304 &coeffs_index, &dev_index,
270 &coeff[0], 305 &coeff[0],
271 &coeff[1], 306 &coeff[1],
272 &coeff[2], 307 &coeff[2],
@@ -288,14 +323,19 @@ static ssize_t set_coeff(struct device *dev,
288 &coeff[18], 323 &coeff[18],
289 &coeff[19]); 324 &coeff[19]);
290 325
291 if (scount != HIST_LEN + 1) 326 if (scount != HIST_LEN + 2)
292 return -1; 327 return -1;
293 328
294 if (devid < 0 || devid >= est->ndevs) 329 if (dev_index < 0 || dev_index >= est->subdevice->num_devs)
330 return -EINVAL;
331
332 if (coeffs_index < 0 || coeffs_index >= est->subdevice->num_coeffs)
295 return -EINVAL; 333 return -EINVAL;
296 334
297 /* This has obvious locking issues but don't worry about it */ 335 /* This has obvious locking issues but don't worry about it */
298 memcpy(est->devs[devid].coeffs, coeff, sizeof(coeff[0]) * HIST_LEN); 336 memcpy(est->subdevice->coeffs_set[coeffs_index].coeffs[dev_index],
337 coeff,
338 sizeof(coeff[0]) * HIST_LEN);
299 339
300 return count; 340 return count;
301} 341}
@@ -304,9 +344,7 @@ static ssize_t show_offset(struct device *dev,
304 struct device_attribute *da, 344 struct device_attribute *da,
305 char *buf) 345 char *buf)
306{ 346{
307 struct therm_estimator *est = dev_get_drvdata(dev); 347 return show_coeff(dev, da, buf);
308 snprintf(buf, PAGE_SIZE, "%ld\n", est->toffset);
309 return strlen(buf);
310} 348}
311 349
312static ssize_t set_offset(struct device *dev, 350static ssize_t set_offset(struct device *dev,
@@ -314,12 +352,68 @@ static ssize_t set_offset(struct device *dev,
314 const char *buf, size_t count) 352 const char *buf, size_t count)
315{ 353{
316 struct therm_estimator *est = dev_get_drvdata(dev); 354 struct therm_estimator *est = dev_get_drvdata(dev);
317 int offset; 355 int offset, scount, coeffs_index;
318 356
319 if (kstrtoint(buf, 0, &offset)) 357 scount = sscanf(buf, "[%d] %d", &coeffs_index, &offset);
358 if (scount != 2)
320 return -EINVAL; 359 return -EINVAL;
321 360
322 est->toffset = offset; 361 if (coeffs_index < 0 || coeffs_index >= est->subdevice->num_coeffs)
362 return -EINVAL;
363
364 est->subdevice->coeffs_set[coeffs_index].toffset = offset;
365
366 return count;
367}
368
369static ssize_t show_active_coeffs(struct device *dev,
370 struct device_attribute *da,
371 char *buf)
372{
373 struct therm_estimator *est = dev_get_drvdata(dev);
374 struct therm_est_subdevice *subdevice = est->subdevice;
375 struct therm_est_coeffs *coeffs_set;
376 long *coeffs;
377 ssize_t total_len = 0;
378 int i, j;
379
380 total_len += snprintf(buf + total_len, PAGE_SIZE - total_len,
381 "There are %d set(s) and the active set is [%02d]\n\n",
382 subdevice->num_coeffs, subdevice->active_coeffs);
383
384 coeffs_set = subdevice->coeffs_set + subdevice->active_coeffs;
385 for (i = 0; i < subdevice->num_devs; i++) {
386 total_len += snprintf(buf + total_len, PAGE_SIZE - total_len,
387 "%s : ", subdevice->sub_thz[i].thz->type);
388 coeffs = coeffs_set->coeffs[i];
389 for (j = 0; j < HIST_LEN; j++) {
390 total_len += snprintf(buf + total_len,
391 PAGE_SIZE - total_len, " %ld",
392 coeffs[j]);
393 }
394 total_len += snprintf(buf + total_len,
395 PAGE_SIZE - total_len, "\n");
396 }
397 total_len += snprintf(buf + total_len, PAGE_SIZE - total_len,
398 "toffset : %ld\n",
399 coeffs_set->toffset);
400
401 return strlen(buf);
402}
403
404static ssize_t set_active_coeffs(struct device *dev,
405 struct device_attribute *da,
406 const char *buf, size_t count)
407{
408 struct therm_estimator *est = dev_get_drvdata(dev);
409 int active_coeffs, ret;
410
411 if (kstrtoint(buf, 0, &active_coeffs))
412 return -EINVAL;
413
414 ret = switch_active_coeffs(est, active_coeffs);
415 if (ret)
416 return ret;
323 417
324 return count; 418 return count;
325} 419}
@@ -329,19 +423,22 @@ static ssize_t show_temps(struct device *dev,
329 char *buf) 423 char *buf)
330{ 424{
331 struct therm_estimator *est = dev_get_drvdata(dev); 425 struct therm_estimator *est = dev_get_drvdata(dev);
426 struct therm_est_subdevice *subdevice = est->subdevice;
427 long *hist;
332 ssize_t total_len = 0; 428 ssize_t total_len = 0;
333 int i, j; 429 int i, j;
334 int index; 430 int index;
335 431
336 /* This has obvious locking issues but don't worry about it */ 432 /* This has obvious locking issues but don't worry about it */
337 for (i = 0; i < est->ndevs; i++) { 433 for (i = 0; i < subdevice->num_devs; i++) {
338 total_len += snprintf(buf + total_len, 434 total_len += snprintf(buf + total_len,
339 PAGE_SIZE - total_len, "[%d]", i); 435 PAGE_SIZE - total_len, "[%d]", i);
436 hist = subdevice->sub_thz[i].hist;
340 for (j = 0; j < HIST_LEN; j++) { 437 for (j = 0; j < HIST_LEN; j++) {
341 index = (est->ntemp - j + HIST_LEN) % HIST_LEN; 438 index = (subdevice->ntemp - j + HIST_LEN) % HIST_LEN;
342 total_len += snprintf(buf + total_len, 439 total_len += snprintf(buf + total_len,
343 PAGE_SIZE - total_len, " %ld", 440 PAGE_SIZE - total_len, " %ld",
344 est->devs[i].hist[index]); 441 hist[index]);
345 } 442 }
346 total_len += snprintf(buf + total_len, 443 total_len += snprintf(buf + total_len,
347 PAGE_SIZE - total_len, "\n"); 444 PAGE_SIZE - total_len, "\n");
@@ -400,6 +497,8 @@ static ssize_t set_tc2(struct device *dev,
400static struct sensor_device_attribute therm_est_nodes[] = { 497static struct sensor_device_attribute therm_est_nodes[] = {
401 SENSOR_ATTR(coeff, S_IRUGO | S_IWUSR, show_coeff, set_coeff, 0), 498 SENSOR_ATTR(coeff, S_IRUGO | S_IWUSR, show_coeff, set_coeff, 0),
402 SENSOR_ATTR(offset, S_IRUGO | S_IWUSR, show_offset, set_offset, 0), 499 SENSOR_ATTR(offset, S_IRUGO | S_IWUSR, show_offset, set_offset, 0),
500 SENSOR_ATTR(active_coeffs, S_IRUGO | S_IWUSR, show_active_coeffs,
501 set_active_coeffs, 0),
403 SENSOR_ATTR(tc1, S_IRUGO | S_IWUSR, show_tc1, set_tc1, 0), 502 SENSOR_ATTR(tc1, S_IRUGO | S_IWUSR, show_tc1, set_tc1, 0),
404 SENSOR_ATTR(tc2, S_IRUGO | S_IWUSR, show_tc2, set_tc2, 0), 503 SENSOR_ATTR(tc2, S_IRUGO | S_IWUSR, show_tc2, set_tc2, 0),
405 SENSOR_ATTR(temps, S_IRUGO, show_temps, 0, 0), 504 SENSOR_ATTR(temps, S_IRUGO, show_temps, 0, 0),
@@ -485,57 +584,110 @@ struct thermal_cooling_device *thermal_est_activation_device_register(
485 return cdev; 584 return cdev;
486} 585}
487 586
488static int __parse_dt_subdev(struct device_node *np, 587static int therm_est_get_subdev(struct device *dev,
489 struct therm_est_subdevice *subdev) 588 struct device_node *subdev_np,
589 struct therm_est_subdevice *subdevice)
490{ 590{
491 const char *str; 591 struct thermal_zone_device *thz;
492 char *sbegin; 592 struct device_node *coeffs_np;
493 int i = 0; 593 char *thz_name;
494 int ret; 594 u32 *values;
595 long *coeffs;
596 int num_subdevs;
597 int num_coeffs;
598 int i, j, ret = 0;
599 s32 val;
600
601 num_subdevs = of_property_count_strings(subdev_np, "subdev_names");
602 if (num_subdevs == 0)
603 return -ENOENT;
604
605 num_coeffs = of_get_child_count(subdev_np);
606 if (num_coeffs == 0)
607 return -ENOENT;
608
609 subdevice->sub_thz = devm_kzalloc(dev,
610 sizeof(*subdevice->sub_thz) * num_subdevs, GFP_KERNEL);
611 if (!subdevice->sub_thz)
612 return -ENOMEM;
495 613
496 subdev->dev_data = (void *)of_get_property(np, "dev-data", NULL); 614 subdevice->coeffs_set = devm_kzalloc(dev,
497 if (!subdev->dev_data) 615 sizeof(*subdevice->coeffs_set) * num_coeffs,
498 return -ENODATA; 616 GFP_KERNEL);
617 if (!subdevice->coeffs_set)
618 return -ENOMEM;
499 619
500 ret = of_property_read_string(np, "coeffs", &str); 620 for (i = 0; i < num_coeffs; i++) {
501 if (ret < 0) 621 subdevice->coeffs_set[i].coeffs = devm_kzalloc(dev,
502 return ret; 622 sizeof(*subdevice->coeffs_set->coeffs) * num_subdevs,
623 GFP_KERNEL);
624 if (!subdevice->coeffs_set[i].coeffs)
625 return -ENOMEM;
626 }
503 627
504 while (str && (i < HIST_LEN)) { 628 for (i = 0; i < num_subdevs; i++) {
505 str = skip_spaces(str); 629 ret = of_property_read_string_index(subdev_np,
506 sbegin = strsep((char **)&str, " "); 630 "subdev_names",
507 if (!sbegin || (kstrtol((const char *)sbegin, 10, 631 i, (const char**)&thz_name);
508 &subdev->coeffs[i++]) < 0)) 632 if (ret)
509 break; 633 return -EINVAL;
634
635 thz = thermal_zone_device_find(thz_name,
636 therm_est_subdev_match);
637 if (!thz)
638 return -EINVAL;
639 subdevice->sub_thz[i].thz = thz;
510 } 640 }
511 if (i != HIST_LEN)
512 return -EINVAL;
513 641
514 return 0; 642 values = kzalloc(sizeof(u32) * num_subdevs * HIST_LEN, GFP_KERNEL);
643 if (!values)
644 return -ENOMEM;
645 i = 0;
646 for_each_child_of_node(subdev_np, coeffs_np) {
647 ret = of_property_read_s32(coeffs_np, "toffset", &val);
648 if (ret)
649 goto err;
650
651 subdevice->coeffs_set[i].toffset = val;
652 ret = of_property_read_u32_array(coeffs_np, "coeffs", values,
653 num_subdevs * HIST_LEN);
654 if (ret)
655 goto err;
656
657 coeffs = (long*)subdevice->coeffs_set[i].coeffs;
658 for (j = 0; j < num_subdevs * HIST_LEN; j++) {
659 val = values[j];
660 coeffs[j] = (s32)((val & 0x80000000U) ?
661 -((val ^ 0xFFFFFFFFU) + 1) : val);
662 }
663
664 i++;
665 }
666 of_node_put(coeffs_np);
667
668 subdevice->num_coeffs = num_coeffs;
669 subdevice->num_devs = num_subdevs;
670
671err:
672 kfree(values);
673 return ret;
515} 674}
516 675
517static struct therm_est_data *therm_est_get_pdata(struct device *dev) 676static struct therm_est_data *therm_est_get_pdata(struct device *dev)
518{ 677{
678 struct device_node *np, *subdev_np;
519 struct therm_est_data *data; 679 struct therm_est_data *data;
520 struct device_node *np;
521 struct device_node *ch;
522 u32 val; 680 u32 val;
523 int num_subdev;
524 int ret; 681 int ret;
525 682
526 np = dev->of_node; 683 np = dev->of_node;
527 if (!np) 684 if (!np)
528 return dev->platform_data; 685 return ERR_PTR(-ENOENT);
529 686
530 data = devm_kzalloc(dev, sizeof(struct therm_est_data), GFP_KERNEL); 687 data = devm_kzalloc(dev, sizeof(struct therm_est_data), GFP_KERNEL);
531 if (!data) 688 if (!data)
532 return ERR_PTR(-ENOMEM); 689 return ERR_PTR(-ENOMEM);
533 690
534 ret = of_property_read_u32(np, "toffset", &val);
535 if (ret < 0)
536 return ERR_PTR(ret);
537 data->toffset = val;
538
539 ret = of_property_read_u32(np, "polling-period", &val); 691 ret = of_property_read_u32(np, "polling-period", &val);
540 if (ret < 0) 692 if (ret < 0)
541 return ERR_PTR(ret); 693 return ERR_PTR(ret);
@@ -556,30 +708,15 @@ static struct therm_est_data *therm_est_get_pdata(struct device *dev)
556 return ERR_PTR(ret); 708 return ERR_PTR(ret);
557 data->use_activator = val; 709 data->use_activator = val;
558 710
559 num_subdev = 0; 711 subdev_np = of_get_child_by_name(np, "subdev");
560 ch = np; 712 if (!subdev_np)
561 while ((ch = of_find_node_by_type(ch, "therm-est-subdev")))
562 num_subdev++;
563
564 /* subdevices are must required data. */
565 if (num_subdev == 0)
566 return ERR_PTR(-ENOENT); 713 return ERR_PTR(-ENOENT);
567 714
568 data->devs = devm_kzalloc(dev, 715 ret = therm_est_get_subdev(dev, subdev_np, &data->subdevice);
569 sizeof(struct therm_est_subdevice) * num_subdev, 716 if (ret)
570 GFP_KERNEL); 717 return ERR_PTR(ret);
571 if (!data->devs)
572 return ERR_PTR(-ENOMEM);
573
574 num_subdev = 0;
575 ch = np;
576 while ((ch = of_find_node_by_type(ch, "therm-est-subdev"))) {
577 ret = __parse_dt_subdev(ch, &data->devs[num_subdev++]);
578 if (ret < 0)
579 return ERR_PTR(ret);
580 }
581 718
582 data->ndevs = num_subdev; 719 of_node_put(subdev_np);
583 720
584 return data; 721 return data;
585} 722}
@@ -595,7 +732,6 @@ static int therm_est_probe(struct platform_device *pdev)
595 int i, ret; 732 int i, ret;
596 struct therm_estimator *est; 733 struct therm_estimator *est;
597 struct therm_est_data *data; 734 struct therm_est_data *data;
598 struct thermal_zone_device *thz;
599 735
600 est = kzalloc(sizeof(struct therm_estimator), GFP_KERNEL); 736 est = kzalloc(sizeof(struct therm_estimator), GFP_KERNEL);
601 if (IS_ERR_OR_NULL(est)) 737 if (IS_ERR_OR_NULL(est))
@@ -604,22 +740,14 @@ static int therm_est_probe(struct platform_device *pdev)
604 platform_set_drvdata(pdev, est); 740 platform_set_drvdata(pdev, est);
605 741
606 data = pdev->dev.platform_data; 742 data = pdev->dev.platform_data;
607 if (!data) 743 if (!data) {
608 data = therm_est_get_pdata(&pdev->dev); 744 data = therm_est_get_pdata(&pdev->dev);
609 745 if (!data)
610 for (i = 0; i < data->ndevs; i++) {
611 thz = thermal_zone_device_find(data->devs[i].dev_data,
612 therm_est_subdev_match);
613 if (!thz)
614 goto err; 746 goto err;
615 data->devs[i].sub_thz = thz;
616 } 747 }
617 748
618 est->devs = data->devs; 749 est->subdevice = &data->subdevice;
619 est->ndevs = data->ndevs;
620 est->toffset = data->toffset;
621 est->polling_period = data->polling_period; 750 est->polling_period = data->polling_period;
622 est->polling_enabled = 0; /* By default polling is switched off */
623 est->tc1 = data->tc1; 751 est->tc1 = data->tc1;
624 est->tc2 = data->tc2; 752 est->tc2 = data->tc2;
625 est->cur_temp = DEFAULT_TSKIN; 753 est->cur_temp = DEFAULT_TSKIN;
diff --git a/include/linux/therm_est.h b/include/linux/therm_est.h
index 9630bd046..a67739483 100644
--- a/include/linux/therm_est.h
+++ b/include/linux/therm_est.h
@@ -26,13 +26,25 @@
26#define MAX_ACTIVE_STATES 10 26#define MAX_ACTIVE_STATES 10
27#define MAX_TIMER_TRIPS 10 27#define MAX_TIMER_TRIPS 10
28 28
29struct therm_est_subdevice { 29struct therm_est_sub_thz {
30 void *dev_data; 30 struct thermal_zone_device *thz;
31 struct thermal_zone_device *sub_thz;
32 long coeffs[HIST_LEN];
33 long hist[HIST_LEN]; 31 long hist[HIST_LEN];
34}; 32};
35 33
34struct therm_est_coeffs {
35 long toffset;
36 long (*coeffs)[HIST_LEN];
37};
38
39struct therm_est_subdevice {
40 struct therm_est_sub_thz *sub_thz;
41 struct therm_est_coeffs *coeffs_set;
42 int num_devs;
43 int num_coeffs;
44 int active_coeffs;
45 int ntemp;
46};
47
36/* 48/*
37 * Timer trip provides a way to change trip temp dynamically based on timestamp 49 * Timer trip provides a way to change trip temp dynamically based on timestamp
38 * when the trip is enabled. 50 * when the trip is enabled.
@@ -74,13 +86,11 @@ struct therm_est_data {
74 86
75 /* zone parameters */ 87 /* zone parameters */
76 struct thermal_zone_params *tzp; 88 struct thermal_zone_params *tzp;
77 long toffset;
78 long polling_period; 89 long polling_period;
79 int passive_delay; 90 int passive_delay;
80 int tc1; 91 int tc1;
81 int tc2; 92 int tc2;
82 int ndevs; 93 struct therm_est_subdevice subdevice;
83 struct therm_est_subdevice *devs;
84 int use_activator; 94 int use_activator;
85}; 95};
86 96