Lines Matching +full:thermal +full:- +full:sensor

1 // SPDX-License-Identifier: GPL-2.0
3 * of-thermal.c - Generic Thermal Management device tree support.
16 #include <linux/thermal.h>
22 /*** Private data structures to represent thermal device tree data ***/
25 * struct __thermal_cooling_bind_param - a cooling device for a trip point
38 * struct __thermal_bind_param - a match between trip and cooling device
53 * struct __thermal_zone - internal representation of a thermal zone
59 * @trips: an array of trip points (0..ntrips - 1)
60 * @num_tbps: number of thermal bind params
61 * @tbps: an array of thermal bind params (0..num_tbps - 1)
62 * @sensor_data: sensor private data used while reading temperature and trend
63 * @ops: set of callbacks to handle the thermal zone based on DT
80 /* sensor interface */
85 /*** DT thermal zone device callbacks ***/
90 struct __thermal_zone *data = tz->devdata; in of_thermal_get_temp()
92 if (!data->ops->get_temp) in of_thermal_get_temp()
93 return -EINVAL; in of_thermal_get_temp()
95 return data->ops->get_temp(data->sensor_data, temp); in of_thermal_get_temp()
101 struct __thermal_zone *data = tz->devdata; in of_thermal_set_trips()
103 if (!data->ops || !data->ops->set_trips) in of_thermal_set_trips()
104 return -EINVAL; in of_thermal_set_trips()
106 return data->ops->set_trips(data->sensor_data, low, high); in of_thermal_set_trips()
110 * of_thermal_get_ntrips - function to export number of available trip
112 * @tz: pointer to a thermal zone
117 * Return: number of available trip points, -ENODEV when data not available
121 struct __thermal_zone *data = tz->devdata; in of_thermal_get_ntrips()
124 return -ENODEV; in of_thermal_get_ntrips()
126 return data->ntrips; in of_thermal_get_ntrips()
131 * of_thermal_is_trip_valid - function to check if trip point is valid
133 * @tz: pointer to a thermal zone
142 struct __thermal_zone *data = tz->devdata; in of_thermal_is_trip_valid()
144 if (!data || trip >= data->ntrips || trip < 0) in of_thermal_is_trip_valid()
152 * of_thermal_get_trip_points - function to get access to a globally exported
155 * @tz: pointer to a thermal zone
164 struct __thermal_zone *data = tz->devdata; in of_thermal_get_trip_points()
169 return data->trips; in of_thermal_get_trip_points()
174 * of_thermal_set_emul_temp - function to set emulated temperature
176 * @tz: pointer to a thermal zone
187 struct __thermal_zone *data = tz->devdata; in of_thermal_set_emul_temp()
189 return data->ops->set_emul_temp(data->sensor_data, temp); in of_thermal_set_emul_temp()
195 struct __thermal_zone *data = tz->devdata; in of_thermal_get_trend()
197 if (!data->ops->get_trend) in of_thermal_get_trend()
198 return -EINVAL; in of_thermal_get_trend()
200 return data->ops->get_trend(data->sensor_data, trip, trend); in of_thermal_get_trend()
203 static int of_thermal_bind(struct thermal_zone_device *thermal, in of_thermal_bind() argument
206 struct __thermal_zone *data = thermal->devdata; in of_thermal_bind()
212 return -ENODEV; in of_thermal_bind()
215 for (i = 0; i < data->num_tbps; i++) { in of_thermal_bind()
216 tbp = data->tbps + i; in of_thermal_bind()
218 for (j = 0; j < tbp->count; j++) { in of_thermal_bind()
219 tcbp = tbp->tcbp + j; in of_thermal_bind()
221 if (tcbp->cooling_device == cdev->np) { in of_thermal_bind()
224 ret = thermal_zone_bind_cooling_device(thermal, in of_thermal_bind()
225 tbp->trip_id, cdev, in of_thermal_bind()
226 tcbp->max, in of_thermal_bind()
227 tcbp->min, in of_thermal_bind()
228 tbp->usage); in of_thermal_bind()
238 static int of_thermal_unbind(struct thermal_zone_device *thermal, in of_thermal_unbind() argument
241 struct __thermal_zone *data = thermal->devdata; in of_thermal_unbind()
247 return -ENODEV; in of_thermal_unbind()
250 for (i = 0; i < data->num_tbps; i++) { in of_thermal_unbind()
251 tbp = data->tbps + i; in of_thermal_unbind()
253 for (j = 0; j < tbp->count; j++) { in of_thermal_unbind()
254 tcbp = tbp->tcbp + j; in of_thermal_unbind()
256 if (tcbp->cooling_device == cdev->np) { in of_thermal_unbind()
259 ret = thermal_zone_unbind_cooling_device(thermal, in of_thermal_unbind()
260 tbp->trip_id, cdev); in of_thermal_unbind()
273 struct __thermal_zone *data = tz->devdata; in of_thermal_get_trip_type()
275 if (trip >= data->ntrips || trip < 0) in of_thermal_get_trip_type()
276 return -EDOM; in of_thermal_get_trip_type()
278 *type = data->trips[trip].type; in of_thermal_get_trip_type()
286 struct __thermal_zone *data = tz->devdata; in of_thermal_get_trip_temp()
288 if (trip >= data->ntrips || trip < 0) in of_thermal_get_trip_temp()
289 return -EDOM; in of_thermal_get_trip_temp()
291 *temp = data->trips[trip].temperature; in of_thermal_get_trip_temp()
299 struct __thermal_zone *data = tz->devdata; in of_thermal_set_trip_temp()
301 if (trip >= data->ntrips || trip < 0) in of_thermal_set_trip_temp()
302 return -EDOM; in of_thermal_set_trip_temp()
304 if (data->ops->set_trip_temp) { in of_thermal_set_trip_temp()
307 ret = data->ops->set_trip_temp(data->sensor_data, trip, temp); in of_thermal_set_trip_temp()
312 /* thermal framework should take care of data->mask & (1 << trip) */ in of_thermal_set_trip_temp()
313 data->trips[trip].temperature = temp; in of_thermal_set_trip_temp()
321 struct __thermal_zone *data = tz->devdata; in of_thermal_get_trip_hyst()
323 if (trip >= data->ntrips || trip < 0) in of_thermal_get_trip_hyst()
324 return -EDOM; in of_thermal_get_trip_hyst()
326 *hyst = data->trips[trip].hysteresis; in of_thermal_get_trip_hyst()
334 struct __thermal_zone *data = tz->devdata; in of_thermal_set_trip_hyst()
336 if (trip >= data->ntrips || trip < 0) in of_thermal_set_trip_hyst()
337 return -EDOM; in of_thermal_set_trip_hyst()
339 /* thermal framework should take care of data->mask & (1 << trip) */ in of_thermal_set_trip_hyst()
340 data->trips[trip].hysteresis = hyst; in of_thermal_set_trip_hyst()
348 struct __thermal_zone *data = tz->devdata; in of_thermal_get_crit_temp()
351 for (i = 0; i < data->ntrips; i++) in of_thermal_get_crit_temp()
352 if (data->trips[i].type == THERMAL_TRIP_CRITICAL) { in of_thermal_get_crit_temp()
353 *temp = data->trips[i].temperature; in of_thermal_get_crit_temp()
357 return -EINVAL; in of_thermal_get_crit_temp()
372 /*** sensor API ***/
376 struct device_node *sensor, void *data, in thermal_zone_of_add_sensor() argument
382 tzd = thermal_zone_get_zone_by_name(zone->name); in thermal_zone_of_add_sensor()
384 return ERR_PTR(-EPROBE_DEFER); in thermal_zone_of_add_sensor()
386 tz = tzd->devdata; in thermal_zone_of_add_sensor()
389 return ERR_PTR(-EINVAL); in thermal_zone_of_add_sensor()
391 mutex_lock(&tzd->lock); in thermal_zone_of_add_sensor()
392 tz->ops = ops; in thermal_zone_of_add_sensor()
393 tz->sensor_data = data; in thermal_zone_of_add_sensor()
395 tzd->ops->get_temp = of_thermal_get_temp; in thermal_zone_of_add_sensor()
396 tzd->ops->get_trend = of_thermal_get_trend; in thermal_zone_of_add_sensor()
399 * The thermal zone core will calculate the window if they have set the in thermal_zone_of_add_sensor()
402 if (ops->set_trips) in thermal_zone_of_add_sensor()
403 tzd->ops->set_trips = of_thermal_set_trips; in thermal_zone_of_add_sensor()
405 if (ops->set_emul_temp) in thermal_zone_of_add_sensor()
406 tzd->ops->set_emul_temp = of_thermal_set_emul_temp; in thermal_zone_of_add_sensor()
408 mutex_unlock(&tzd->lock); in thermal_zone_of_add_sensor()
414 * thermal_zone_of_get_sensor_id - get sensor ID from a DT thermal zone
415 * @tz_np: a valid thermal zone device node.
416 * @sensor_np: a sensor node of a valid sensor device.
417 * @id: the sensor ID returned if success.
419 * This function will get sensor ID from a given thermal zone node and
420 * the sensor node must match the temperature provider @sensor_np.
433 "thermal-sensors", in thermal_zone_of_get_sensor_id()
434 "#thermal-sensor-cells", in thermal_zone_of_get_sensor_id()
442 return -ENODEV; in thermal_zone_of_get_sensor_id()
446 pr_warn("%pOFn: too many cells in sensor specifier %d\n", in thermal_zone_of_get_sensor_id()
458 * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone
459 * @dev: a valid struct device pointer of a sensor device. Must contain
460 * a valid .of_node, for the sensor node.
461 * @sensor_id: a sensor identifier, in case the sensor IP has more
467 * This function will search the list of thermal zones described in device
468 * tree and look for the zone that refer to the sensor device pointed by
469 * @dev->of_node as temperature providers. For the zone pointing to the
470 * sensor node, the sensor will be added to the DT thermal zone device.
472 * The thermal zone temperature is provided by the @get_temp function
475 * The thermal zone temperature trend is provided by the @get_trend function
479 * 01 - This function must enqueue the new sensor instead of using
482 * 02 - There must be a way to match the sensor with all thermal zones
494 struct thermal_zone_device *tzd = ERR_PTR(-ENODEV); in thermal_zone_of_sensor_register()
496 np = of_find_node_by_name(NULL, "thermal-zones"); in thermal_zone_of_sensor_register()
498 return ERR_PTR(-ENODEV); in thermal_zone_of_sensor_register()
500 if (!dev || !dev->of_node) { in thermal_zone_of_sensor_register()
502 return ERR_PTR(-ENODEV); in thermal_zone_of_sensor_register()
505 sensor_np = of_node_get(dev->of_node); in thermal_zone_of_sensor_register()
510 /* For now, thermal framework supports only 1 sensor per zone */ in thermal_zone_of_sensor_register()
534 * thermal_zone_of_sensor_unregister - unregisters a sensor from a DT thermal zone
535 * @dev: a valid struct device pointer of a sensor device. Must contain
536 * a valid .of_node, for the sensor node.
537 * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
539 * This function removes the sensor callbacks and private data from the
540 * thermal zone device registered with thermal_zone_of_sensor_register()
542 * thermal zone device callbacks.
545 * function must search the sensor list based on @dev parameter.
553 if (!dev || !tzd || !tzd->devdata) in thermal_zone_of_sensor_unregister()
556 tz = tzd->devdata; in thermal_zone_of_sensor_unregister()
562 mutex_lock(&tzd->lock); in thermal_zone_of_sensor_unregister()
563 tzd->ops->get_temp = NULL; in thermal_zone_of_sensor_unregister()
564 tzd->ops->get_trend = NULL; in thermal_zone_of_sensor_unregister()
565 tzd->ops->set_emul_temp = NULL; in thermal_zone_of_sensor_unregister()
567 tz->ops = NULL; in thermal_zone_of_sensor_unregister()
568 tz->sensor_data = NULL; in thermal_zone_of_sensor_unregister()
569 mutex_unlock(&tzd->lock); in thermal_zone_of_sensor_unregister()
591 * devm_thermal_zone_of_sensor_register - Resource managed version of
593 * @dev: a valid struct device pointer of a sensor device. Must contain
594 * a valid .of_node, for the sensor node.
595 * @sensor_id: a sensor identifier, in case the sensor IP has more
618 return ERR_PTR(-ENOMEM); in devm_thermal_zone_of_sensor_register()
634 * devm_thermal_zone_of_sensor_unregister - Resource managed version of
637 * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
639 * This function removes the sensor callbacks and private data from the
640 * thermal zone device registered with devm_thermal_zone_of_sensor_register()
642 * thermal zone device callbacks.
657 * thermal_of_populate_bind_params - parse and fill cooling map data
658 * @np: DT node containing a cooling-map node
660 * @trips: array of thermal zone trip points
663 * This function parses a cooling-map type of node represented by
665 * It needs the already parsed array of trip points of the thermal zone
682 __tbp->usage = THERMAL_WEIGHT_DEFAULT; in thermal_of_populate_bind_params()
685 __tbp->usage = prop; in thermal_of_populate_bind_params()
690 return -ENODEV; in thermal_of_populate_bind_params()
696 __tbp->trip_id = i; in thermal_of_populate_bind_params()
701 ret = -ENODEV; in thermal_of_populate_bind_params()
705 count = of_count_phandle_with_args(np, "cooling-device", in thermal_of_populate_bind_params()
706 "#cooling-cells"); in thermal_of_populate_bind_params()
717 ret = of_parse_phandle_with_args(np, "cooling-device", in thermal_of_populate_bind_params()
718 "#cooling-cells", i, &cooling_spec); in thermal_of_populate_bind_params()
720 pr_err("Invalid cooling-device entry\n"); in thermal_of_populate_bind_params()
734 __tbp->tcbp = __tcbp; in thermal_of_populate_bind_params()
735 __tbp->count = count; in thermal_of_populate_bind_params()
740 for (i = i - 1; i >= 0; i--) in thermal_of_populate_bind_params()
750 * It maps 'enum thermal_trip_type' found in include/linux/thermal.h
761 * thermal_of_get_trip_type - Get phy mode for given device_node
786 return -ENODEV; in thermal_of_get_trip_type()
790 * thermal_of_populate_trip - parse and fill one trip point data
810 trip->temperature = prop; in thermal_of_populate_trip()
817 trip->hysteresis = prop; in thermal_of_populate_trip()
819 ret = thermal_of_get_trip_type(np, &trip->type); in thermal_of_populate_trip()
826 trip->np = np; in thermal_of_populate_trip()
833 * thermal_of_build_thermal_zone - parse and fill one thermal zone data
834 * @np: DT node containing a thermal zone node
836 * This function parses a thermal zone type of node represented by
840 * TODO: Missing properties to parse: thermal-sensor-names
855 pr_err("no thermal zone np\n"); in thermal_of_build_thermal_zone()
856 return ERR_PTR(-EINVAL); in thermal_of_build_thermal_zone()
861 return ERR_PTR(-ENOMEM); in thermal_of_build_thermal_zone()
863 ret = of_property_read_u32(np, "polling-delay-passive", &prop); in thermal_of_build_thermal_zone()
865 pr_err("%pOFn: missing polling-delay-passive property\n", np); in thermal_of_build_thermal_zone()
868 tz->passive_delay = prop; in thermal_of_build_thermal_zone()
870 ret = of_property_read_u32(np, "polling-delay", &prop); in thermal_of_build_thermal_zone()
872 pr_err("%pOFn: missing polling-delay property\n", np); in thermal_of_build_thermal_zone()
875 tz->polling_delay = prop; in thermal_of_build_thermal_zone()
878 * REVIST: for now, the thermal framework supports only in thermal_of_build_thermal_zone()
879 * one sensor per thermal zone. Thus, we are considering in thermal_of_build_thermal_zone()
884 tz->slope = coef[0]; in thermal_of_build_thermal_zone()
885 tz->offset = coef[1]; in thermal_of_build_thermal_zone()
887 tz->slope = 1; in thermal_of_build_thermal_zone()
888 tz->offset = 0; in thermal_of_build_thermal_zone()
898 tz->ntrips = of_get_child_count(child); in thermal_of_build_thermal_zone()
899 if (tz->ntrips == 0) /* must have at least one child */ in thermal_of_build_thermal_zone()
902 tz->trips = kcalloc(tz->ntrips, sizeof(*tz->trips), GFP_KERNEL); in thermal_of_build_thermal_zone()
903 if (!tz->trips) { in thermal_of_build_thermal_zone()
904 ret = -ENOMEM; in thermal_of_build_thermal_zone()
910 ret = thermal_of_populate_trip(gchild, &tz->trips[i++]); in thermal_of_build_thermal_zone()
917 /* cooling-maps */ in thermal_of_build_thermal_zone()
918 child = of_get_child_by_name(np, "cooling-maps"); in thermal_of_build_thermal_zone()
920 /* cooling-maps not provided */ in thermal_of_build_thermal_zone()
924 tz->num_tbps = of_get_child_count(child); in thermal_of_build_thermal_zone()
925 if (tz->num_tbps == 0) in thermal_of_build_thermal_zone()
928 tz->tbps = kcalloc(tz->num_tbps, sizeof(*tz->tbps), GFP_KERNEL); in thermal_of_build_thermal_zone()
929 if (!tz->tbps) { in thermal_of_build_thermal_zone()
930 ret = -ENOMEM; in thermal_of_build_thermal_zone()
936 ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++], in thermal_of_build_thermal_zone()
937 tz->trips, tz->ntrips); in thermal_of_build_thermal_zone()
948 for (i = i - 1; i >= 0; i--) { in thermal_of_build_thermal_zone()
949 struct __thermal_bind_params *tbp = tz->tbps + i; in thermal_of_build_thermal_zone()
952 for (j = 0; j < tbp->count; j++) in thermal_of_build_thermal_zone()
953 of_node_put(tbp->tcbp[j].cooling_device); in thermal_of_build_thermal_zone()
955 kfree(tbp->tcbp); in thermal_of_build_thermal_zone()
958 kfree(tz->tbps); in thermal_of_build_thermal_zone()
960 for (i = 0; i < tz->ntrips; i++) in thermal_of_build_thermal_zone()
961 of_node_put(tz->trips[i].np); in thermal_of_build_thermal_zone()
962 kfree(tz->trips); in thermal_of_build_thermal_zone()
976 for (i = 0; i < tz->num_tbps; i++) { in of_thermal_free_zone()
977 tbp = tz->tbps + i; in of_thermal_free_zone()
979 for (j = 0; j < tbp->count; j++) in of_thermal_free_zone()
980 of_node_put(tbp->tcbp[j].cooling_device); in of_thermal_free_zone()
982 kfree(tbp->tcbp); in of_thermal_free_zone()
985 kfree(tz->tbps); in of_thermal_free_zone()
986 for (i = 0; i < tz->ntrips; i++) in of_thermal_free_zone()
987 of_node_put(tz->trips[i].np); in of_thermal_free_zone()
988 kfree(tz->trips); in of_thermal_free_zone()
993 * of_thermal_destroy_zones - remove all zones parsed and allocated resources
995 * Finds all zones parsed and added to the thermal framework and remove them
1003 np = of_find_node_by_name(NULL, "thermal-zones"); in of_thermal_destroy_zones()
1005 pr_debug("unable to find thermal zones\n"); in of_thermal_destroy_zones()
1012 zone = thermal_zone_get_zone_by_name(child->name); in of_thermal_destroy_zones()
1017 kfree(zone->tzp); in of_thermal_destroy_zones()
1018 kfree(zone->ops); in of_thermal_destroy_zones()
1019 of_thermal_free_zone(zone->devdata); in of_thermal_destroy_zones()
1025 * of_parse_thermal_zones - parse device tree thermal data
1028 * code to parse thermal data and populate the thermal framework
1029 * with hardware thermal zones info. This function only parses thermal zones.
1030 * Cooling devices and sensor devices nodes are supposed to be parsed
1042 np = of_find_node_by_name(NULL, "thermal-zones"); in of_parse_thermal_zones()
1044 pr_debug("unable to find thermal zones\n"); in of_parse_thermal_zones()
1045 return 0; /* Run successfully on systems without thermal DT */ in of_parse_thermal_zones()
1056 pr_err("failed to build thermal zone %pOFn: %ld\n", in of_parse_thermal_zones()
1073 tzp->no_hwmon = true; in of_parse_thermal_zones()
1075 if (!of_property_read_u32(child, "sustainable-power", &prop)) in of_parse_thermal_zones()
1076 tzp->sustainable_power = prop; in of_parse_thermal_zones()
1078 for (i = 0; i < tz->ntrips; i++) in of_parse_thermal_zones()
1082 tzp->slope = tz->slope; in of_parse_thermal_zones()
1083 tzp->offset = tz->offset; in of_parse_thermal_zones()
1085 zone = thermal_zone_device_register(child->name, tz->ntrips, in of_parse_thermal_zones()
1088 tz->passive_delay, in of_parse_thermal_zones()
1089 tz->polling_delay); in of_parse_thermal_zones()
1111 return -ENOMEM; in of_parse_thermal_zones()