1
2
3
4
5
6
7
8#include <linux/thermal.h>
9#include <linux/slab.h>
10#include <linux/types.h>
11#include <linux/of_device.h>
12#include <linux/of_platform.h>
13#include <linux/err.h>
14#include <linux/export.h>
15#include <linux/string.h>
16
17#include "thermal_core.h"
18
19
20
21
22
23
24
25
26
27
28
29
30struct __thermal_bind_params {
31 struct device_node *cooling_device;
32 unsigned int trip_id;
33 unsigned int usage;
34 unsigned long min;
35 unsigned long max;
36};
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52struct __thermal_zone {
53 int passive_delay;
54 int polling_delay;
55 int slope;
56 int offset;
57
58
59 int ntrips;
60 struct thermal_trip *trips;
61
62
63 int num_tbps;
64 struct __thermal_bind_params *tbps;
65
66
67 void *sensor_data;
68 const struct thermal_zone_of_device_ops *ops;
69};
70
71
72
73static int of_thermal_get_temp(struct thermal_zone_device *tz,
74 int *temp)
75{
76 struct __thermal_zone *data = tz->devdata;
77
78 if (!data->ops->get_temp)
79 return -EINVAL;
80
81 return data->ops->get_temp(data->sensor_data, temp);
82}
83
84static int of_thermal_set_trips(struct thermal_zone_device *tz,
85 int low, int high)
86{
87 struct __thermal_zone *data = tz->devdata;
88
89 if (!data->ops || !data->ops->set_trips)
90 return -EINVAL;
91
92 return data->ops->set_trips(data->sensor_data, low, high);
93}
94
95
96
97
98
99
100
101
102
103
104
105int of_thermal_get_ntrips(struct thermal_zone_device *tz)
106{
107 struct __thermal_zone *data = tz->devdata;
108
109 if (!data || IS_ERR(data))
110 return -ENODEV;
111
112 return data->ntrips;
113}
114EXPORT_SYMBOL_GPL(of_thermal_get_ntrips);
115
116
117
118
119
120
121
122
123
124
125
126bool of_thermal_is_trip_valid(struct thermal_zone_device *tz, int trip)
127{
128 struct __thermal_zone *data = tz->devdata;
129
130 if (!data || trip >= data->ntrips || trip < 0)
131 return false;
132
133 return true;
134}
135EXPORT_SYMBOL_GPL(of_thermal_is_trip_valid);
136
137
138
139
140
141
142
143
144
145
146
147const struct thermal_trip *
148of_thermal_get_trip_points(struct thermal_zone_device *tz)
149{
150 struct __thermal_zone *data = tz->devdata;
151
152 if (!data)
153 return NULL;
154
155 return data->trips;
156}
157EXPORT_SYMBOL_GPL(of_thermal_get_trip_points);
158
159
160
161
162
163
164
165
166
167
168
169
170static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
171 int temp)
172{
173 struct __thermal_zone *data = tz->devdata;
174
175 return data->ops->set_emul_temp(data->sensor_data, temp);
176}
177
178static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
179 enum thermal_trend *trend)
180{
181 struct __thermal_zone *data = tz->devdata;
182
183 if (!data->ops->get_trend)
184 return -EINVAL;
185
186 return data->ops->get_trend(data->sensor_data, trip, trend);
187}
188
189static int of_thermal_bind(struct thermal_zone_device *thermal,
190 struct thermal_cooling_device *cdev)
191{
192 struct __thermal_zone *data = thermal->devdata;
193 int i;
194
195 if (!data || IS_ERR(data))
196 return -ENODEV;
197
198
199 for (i = 0; i < data->num_tbps; i++) {
200 struct __thermal_bind_params *tbp = data->tbps + i;
201
202 if (tbp->cooling_device == cdev->np) {
203 int ret;
204
205 ret = thermal_zone_bind_cooling_device(thermal,
206 tbp->trip_id, cdev,
207 tbp->max,
208 tbp->min,
209 tbp->usage);
210 if (ret)
211 return ret;
212 }
213 }
214
215 return 0;
216}
217
218static int of_thermal_unbind(struct thermal_zone_device *thermal,
219 struct thermal_cooling_device *cdev)
220{
221 struct __thermal_zone *data = thermal->devdata;
222 int i;
223
224 if (!data || IS_ERR(data))
225 return -ENODEV;
226
227
228 for (i = 0; i < data->num_tbps; i++) {
229 struct __thermal_bind_params *tbp = data->tbps + i;
230
231 if (tbp->cooling_device == cdev->np) {
232 int ret;
233
234 ret = thermal_zone_unbind_cooling_device(thermal,
235 tbp->trip_id, cdev);
236 if (ret)
237 return ret;
238 }
239 }
240
241 return 0;
242}
243
244static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
245 enum thermal_trip_type *type)
246{
247 struct __thermal_zone *data = tz->devdata;
248
249 if (trip >= data->ntrips || trip < 0)
250 return -EDOM;
251
252 *type = data->trips[trip].type;
253
254 return 0;
255}
256
257static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
258 int *temp)
259{
260 struct __thermal_zone *data = tz->devdata;
261
262 if (trip >= data->ntrips || trip < 0)
263 return -EDOM;
264
265 *temp = data->trips[trip].temperature;
266
267 return 0;
268}
269
270static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
271 int temp)
272{
273 struct __thermal_zone *data = tz->devdata;
274
275 if (trip >= data->ntrips || trip < 0)
276 return -EDOM;
277
278 if (data->ops->set_trip_temp) {
279 int ret;
280
281 ret = data->ops->set_trip_temp(data->sensor_data, trip, temp);
282 if (ret)
283 return ret;
284 }
285
286
287 data->trips[trip].temperature = temp;
288
289 return 0;
290}
291
292static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
293 int *hyst)
294{
295 struct __thermal_zone *data = tz->devdata;
296
297 if (trip >= data->ntrips || trip < 0)
298 return -EDOM;
299
300 *hyst = data->trips[trip].hysteresis;
301
302 return 0;
303}
304
305static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
306 int hyst)
307{
308 struct __thermal_zone *data = tz->devdata;
309
310 if (trip >= data->ntrips || trip < 0)
311 return -EDOM;
312
313
314 data->trips[trip].hysteresis = hyst;
315
316 return 0;
317}
318
319static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
320 int *temp)
321{
322 struct __thermal_zone *data = tz->devdata;
323 int i;
324
325 for (i = 0; i < data->ntrips; i++)
326 if (data->trips[i].type == THERMAL_TRIP_CRITICAL) {
327 *temp = data->trips[i].temperature;
328 return 0;
329 }
330
331 return -EINVAL;
332}
333
334static struct thermal_zone_device_ops of_thermal_ops = {
335 .get_trip_type = of_thermal_get_trip_type,
336 .get_trip_temp = of_thermal_get_trip_temp,
337 .set_trip_temp = of_thermal_set_trip_temp,
338 .get_trip_hyst = of_thermal_get_trip_hyst,
339 .set_trip_hyst = of_thermal_set_trip_hyst,
340 .get_crit_temp = of_thermal_get_crit_temp,
341
342 .bind = of_thermal_bind,
343 .unbind = of_thermal_unbind,
344};
345
346
347
348static struct thermal_zone_device *
349thermal_zone_of_add_sensor(struct device_node *zone,
350 struct device_node *sensor, void *data,
351 const struct thermal_zone_of_device_ops *ops)
352{
353 struct thermal_zone_device *tzd;
354 struct __thermal_zone *tz;
355
356 tzd = thermal_zone_get_zone_by_name(zone->name);
357 if (IS_ERR(tzd))
358 return ERR_PTR(-EPROBE_DEFER);
359
360 tz = tzd->devdata;
361
362 if (!ops)
363 return ERR_PTR(-EINVAL);
364
365 mutex_lock(&tzd->lock);
366 tz->ops = ops;
367 tz->sensor_data = data;
368
369 tzd->ops->get_temp = of_thermal_get_temp;
370 tzd->ops->get_trend = of_thermal_get_trend;
371
372
373
374
375
376 if (ops->set_trips)
377 tzd->ops->set_trips = of_thermal_set_trips;
378
379 if (ops->set_emul_temp)
380 tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
381
382 mutex_unlock(&tzd->lock);
383
384 return tzd;
385}
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419struct thermal_zone_device *
420thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
421 const struct thermal_zone_of_device_ops *ops)
422{
423 struct device_node *np, *child, *sensor_np;
424 struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
425
426 np = of_find_node_by_name(NULL, "thermal-zones");
427 if (!np)
428 return ERR_PTR(-ENODEV);
429
430 if (!dev || !dev->of_node) {
431 of_node_put(np);
432 return ERR_PTR(-EINVAL);
433 }
434
435 sensor_np = of_node_get(dev->of_node);
436
437 for_each_available_child_of_node(np, child) {
438 struct of_phandle_args sensor_specs;
439 int ret, id;
440
441
442 ret = of_parse_phandle_with_args(child, "thermal-sensors",
443 "#thermal-sensor-cells",
444 0, &sensor_specs);
445 if (ret)
446 continue;
447
448 if (sensor_specs.args_count >= 1) {
449 id = sensor_specs.args[0];
450 WARN(sensor_specs.args_count > 1,
451 "%s: too many cells in sensor specifier %d\n",
452 sensor_specs.np->name, sensor_specs.args_count);
453 } else {
454 id = 0;
455 }
456
457 if (sensor_specs.np == sensor_np && id == sensor_id) {
458 tzd = thermal_zone_of_add_sensor(child, sensor_np,
459 data, ops);
460 if (!IS_ERR(tzd))
461 thermal_zone_device_enable(tzd);
462
463 of_node_put(sensor_specs.np);
464 of_node_put(child);
465 goto exit;
466 }
467 of_node_put(sensor_specs.np);
468 }
469exit:
470 of_node_put(sensor_np);
471 of_node_put(np);
472
473 return tzd;
474}
475EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_register);
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492void thermal_zone_of_sensor_unregister(struct device *dev,
493 struct thermal_zone_device *tzd)
494{
495 struct __thermal_zone *tz;
496
497 if (!dev || !tzd || !tzd->devdata)
498 return;
499
500 tz = tzd->devdata;
501
502
503 if (!tz)
504 return;
505
506 mutex_lock(&tzd->lock);
507 tzd->ops->get_temp = NULL;
508 tzd->ops->get_trend = NULL;
509 tzd->ops->set_emul_temp = NULL;
510
511 tz->ops = NULL;
512 tz->sensor_data = NULL;
513 mutex_unlock(&tzd->lock);
514}
515EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
516
517static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res)
518{
519 thermal_zone_of_sensor_unregister(dev,
520 *(struct thermal_zone_device **)res);
521}
522
523static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res,
524 void *data)
525{
526 struct thermal_zone_device **r = res;
527
528 if (WARN_ON(!r || !*r))
529 return 0;
530
531 return *r == data;
532}
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
554 struct device *dev, int sensor_id,
555 void *data, const struct thermal_zone_of_device_ops *ops)
556{
557 struct thermal_zone_device **ptr, *tzd;
558
559 ptr = devres_alloc(devm_thermal_zone_of_sensor_release, sizeof(*ptr),
560 GFP_KERNEL);
561 if (!ptr)
562 return ERR_PTR(-ENOMEM);
563
564 tzd = thermal_zone_of_sensor_register(dev, sensor_id, data, ops);
565 if (IS_ERR(tzd)) {
566 devres_free(ptr);
567 return tzd;
568 }
569
570 *ptr = tzd;
571 devres_add(dev, ptr);
572
573 return tzd;
574}
575EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_register);
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590void devm_thermal_zone_of_sensor_unregister(struct device *dev,
591 struct thermal_zone_device *tzd)
592{
593 WARN_ON(devres_release(dev, devm_thermal_zone_of_sensor_release,
594 devm_thermal_zone_of_sensor_match, tzd));
595}
596EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister);
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614static int thermal_of_populate_bind_params(struct device_node *np,
615 struct __thermal_bind_params *__tbp,
616 struct thermal_trip *trips,
617 int ntrips)
618{
619 struct of_phandle_args cooling_spec;
620 struct device_node *trip;
621 int ret, i;
622 u32 prop;
623
624
625 __tbp->usage = THERMAL_WEIGHT_DEFAULT;
626 ret = of_property_read_u32(np, "contribution", &prop);
627 if (ret == 0)
628 __tbp->usage = prop;
629
630 trip = of_parse_phandle(np, "trip", 0);
631 if (!trip) {
632 pr_err("missing trip property\n");
633 return -ENODEV;
634 }
635
636
637 for (i = 0; i < ntrips; i++)
638 if (trip == trips[i].np) {
639 __tbp->trip_id = i;
640 break;
641 }
642
643 if (i == ntrips) {
644 ret = -ENODEV;
645 goto end;
646 }
647
648 ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells",
649 0, &cooling_spec);
650 if (ret < 0) {
651 pr_err("missing cooling_device property\n");
652 goto end;
653 }
654 __tbp->cooling_device = cooling_spec.np;
655 if (cooling_spec.args_count >= 2) {
656 __tbp->min = cooling_spec.args[0];
657 __tbp->max = cooling_spec.args[1];
658 } else {
659 pr_err("wrong reference to cooling device, missing limits\n");
660 }
661
662end:
663 of_node_put(trip);
664
665 return ret;
666}
667
668
669
670
671
672static const char * const trip_types[] = {
673 [THERMAL_TRIP_ACTIVE] = "active",
674 [THERMAL_TRIP_PASSIVE] = "passive",
675 [THERMAL_TRIP_HOT] = "hot",
676 [THERMAL_TRIP_CRITICAL] = "critical",
677};
678
679
680
681
682
683
684
685
686
687
688
689static int thermal_of_get_trip_type(struct device_node *np,
690 enum thermal_trip_type *type)
691{
692 const char *t;
693 int err, i;
694
695 err = of_property_read_string(np, "type", &t);
696 if (err < 0)
697 return err;
698
699 for (i = 0; i < ARRAY_SIZE(trip_types); i++)
700 if (!strcasecmp(t, trip_types[i])) {
701 *type = i;
702 return 0;
703 }
704
705 return -ENODEV;
706}
707
708
709
710
711
712
713
714
715
716
717
718static int thermal_of_populate_trip(struct device_node *np,
719 struct thermal_trip *trip)
720{
721 int prop;
722 int ret;
723
724 ret = of_property_read_u32(np, "temperature", &prop);
725 if (ret < 0) {
726 pr_err("missing temperature property\n");
727 return ret;
728 }
729 trip->temperature = prop;
730
731 ret = of_property_read_u32(np, "hysteresis", &prop);
732 if (ret < 0) {
733 pr_err("missing hysteresis property\n");
734 return ret;
735 }
736 trip->hysteresis = prop;
737
738 ret = thermal_of_get_trip_type(np, &trip->type);
739 if (ret < 0) {
740 pr_err("wrong trip type property\n");
741 return ret;
742 }
743
744
745 trip->np = np;
746 of_node_get(np);
747
748 return 0;
749}
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765static struct __thermal_zone
766__init *thermal_of_build_thermal_zone(struct device_node *np)
767{
768 struct device_node *child = NULL, *gchild;
769 struct __thermal_zone *tz;
770 int ret, i;
771 u32 prop, coef[2];
772
773 if (!np) {
774 pr_err("no thermal zone np\n");
775 return ERR_PTR(-EINVAL);
776 }
777
778 tz = kzalloc(sizeof(*tz), GFP_KERNEL);
779 if (!tz)
780 return ERR_PTR(-ENOMEM);
781
782 ret = of_property_read_u32(np, "polling-delay-passive", &prop);
783 if (ret < 0) {
784 pr_err("missing polling-delay-passive property\n");
785 goto free_tz;
786 }
787 tz->passive_delay = prop;
788
789 ret = of_property_read_u32(np, "polling-delay", &prop);
790 if (ret < 0) {
791 pr_err("missing polling-delay property\n");
792 goto free_tz;
793 }
794 tz->polling_delay = prop;
795
796
797
798
799
800
801 ret = of_property_read_u32_array(np, "coefficients", coef, 2);
802 if (ret == 0) {
803 tz->slope = coef[0];
804 tz->offset = coef[1];
805 } else {
806 tz->slope = 1;
807 tz->offset = 0;
808 }
809
810
811 child = of_get_child_by_name(np, "trips");
812
813
814 if (!child)
815 goto finish;
816
817 tz->ntrips = of_get_child_count(child);
818 if (tz->ntrips == 0)
819 goto finish;
820
821 tz->trips = kcalloc(tz->ntrips, sizeof(*tz->trips), GFP_KERNEL);
822 if (!tz->trips) {
823 ret = -ENOMEM;
824 goto free_tz;
825 }
826
827 i = 0;
828 for_each_child_of_node(child, gchild) {
829 ret = thermal_of_populate_trip(gchild, &tz->trips[i++]);
830 if (ret)
831 goto free_trips;
832 }
833
834 of_node_put(child);
835
836
837 child = of_get_child_by_name(np, "cooling-maps");
838
839
840 if (!child)
841 goto finish;
842
843 tz->num_tbps = of_get_child_count(child);
844 if (tz->num_tbps == 0)
845 goto finish;
846
847 tz->tbps = kcalloc(tz->num_tbps, sizeof(*tz->tbps), GFP_KERNEL);
848 if (!tz->tbps) {
849 ret = -ENOMEM;
850 goto free_trips;
851 }
852
853 i = 0;
854 for_each_child_of_node(child, gchild) {
855 ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++],
856 tz->trips, tz->ntrips);
857 if (ret)
858 goto free_tbps;
859 }
860
861finish:
862 of_node_put(child);
863
864 return tz;
865
866free_tbps:
867 for (i = i - 1; i >= 0; i--)
868 of_node_put(tz->tbps[i].cooling_device);
869 kfree(tz->tbps);
870free_trips:
871 for (i = 0; i < tz->ntrips; i++)
872 of_node_put(tz->trips[i].np);
873 kfree(tz->trips);
874 of_node_put(gchild);
875free_tz:
876 kfree(tz);
877 of_node_put(child);
878
879 return ERR_PTR(ret);
880}
881
882static inline void of_thermal_free_zone(struct __thermal_zone *tz)
883{
884 int i;
885
886 for (i = 0; i < tz->num_tbps; i++)
887 of_node_put(tz->tbps[i].cooling_device);
888 kfree(tz->tbps);
889 for (i = 0; i < tz->ntrips; i++)
890 of_node_put(tz->trips[i].np);
891 kfree(tz->trips);
892 kfree(tz);
893}
894
895
896
897
898
899
900
901
902
903
904
905
906
907int __init of_parse_thermal_zones(void)
908{
909 struct device_node *np, *child;
910 struct __thermal_zone *tz;
911 struct thermal_zone_device_ops *ops;
912
913 np = of_find_node_by_name(NULL, "thermal-zones");
914 if (!np) {
915 pr_debug("unable to find thermal zones\n");
916 return 0;
917 }
918
919 for_each_available_child_of_node(np, child) {
920 struct thermal_zone_device *zone;
921 struct thermal_zone_params *tzp;
922 int i, mask = 0;
923 u32 prop;
924
925 tz = thermal_of_build_thermal_zone(child);
926 if (IS_ERR(tz)) {
927 pr_err("failed to build thermal zone %s: %ld\n",
928 child->name,
929 PTR_ERR(tz));
930 continue;
931 }
932
933 ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL);
934 if (!ops)
935 goto exit_free;
936
937 tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
938 if (!tzp) {
939 kfree(ops);
940 goto exit_free;
941 }
942
943
944 tzp->no_hwmon = true;
945
946 if (!of_property_read_u32(child, "sustainable-power", &prop))
947 tzp->sustainable_power = prop;
948
949 for (i = 0; i < tz->ntrips; i++)
950 mask |= 1 << i;
951
952
953 tzp->slope = tz->slope;
954 tzp->offset = tz->offset;
955
956 zone = thermal_zone_device_register(child->name, tz->ntrips,
957 mask, tz,
958 ops, tzp,
959 tz->passive_delay,
960 tz->polling_delay);
961 if (IS_ERR(zone)) {
962 pr_err("Failed to build %s zone %ld\n", child->name,
963 PTR_ERR(zone));
964 kfree(tzp);
965 kfree(ops);
966 of_thermal_free_zone(tz);
967
968 }
969 }
970 of_node_put(np);
971
972 return 0;
973
974exit_free:
975 of_node_put(child);
976 of_node_put(np);
977 of_thermal_free_zone(tz);
978
979
980 of_thermal_destroy_zones();
981
982 return -ENOMEM;
983}
984
985
986
987
988
989
990
991
992void of_thermal_destroy_zones(void)
993{
994 struct device_node *np, *child;
995
996 np = of_find_node_by_name(NULL, "thermal-zones");
997 if (!np) {
998 pr_debug("unable to find thermal zones\n");
999 return;
1000 }
1001
1002 for_each_available_child_of_node(np, child) {
1003 struct thermal_zone_device *zone;
1004
1005 zone = thermal_zone_get_zone_by_name(child->name);
1006 if (IS_ERR(zone))
1007 continue;
1008
1009 thermal_zone_device_unregister(zone);
1010 kfree(zone->tzp);
1011 kfree(zone->ops);
1012 of_thermal_free_zone(zone->devdata);
1013 }
1014 of_node_put(np);
1015}
1016