1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2008 Intel Corp 4 * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> 5 * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> 6 * Copyright 2022 Linaro Limited 7 * 8 * Thermal trips handling 9 */ 10 #include "thermal_core.h" 11 12 int for_each_thermal_trip(struct thermal_zone_device *tz, 13 int (*cb)(struct thermal_trip *, void *), 14 void *data) 15 { 16 struct thermal_trip *trip; 17 int ret; 18 19 for_each_trip(tz, trip) { 20 ret = cb(trip, data); 21 if (ret) 22 return ret; 23 } 24 25 return 0; 26 } 27 EXPORT_SYMBOL_GPL(for_each_thermal_trip); 28 29 int thermal_zone_for_each_trip(struct thermal_zone_device *tz, 30 int (*cb)(struct thermal_trip *, void *), 31 void *data) 32 { 33 int ret; 34 35 mutex_lock(&tz->lock); 36 ret = for_each_thermal_trip(tz, cb, data); 37 mutex_unlock(&tz->lock); 38 39 return ret; 40 } 41 EXPORT_SYMBOL_GPL(thermal_zone_for_each_trip); 42 43 int thermal_zone_get_num_trips(struct thermal_zone_device *tz) 44 { 45 return tz->num_trips; 46 } 47 EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips); 48 49 /** 50 * __thermal_zone_set_trips - Computes the next trip points for the driver 51 * @tz: a pointer to a thermal zone device structure 52 * 53 * The function computes the next temperature boundaries by browsing 54 * the trip points. The result is the closer low and high trip points 55 * to the current temperature. These values are passed to the backend 56 * driver to let it set its own notification mechanism (usually an 57 * interrupt). 58 * 59 * This function must be called with tz->lock held. Both tz and tz->ops 60 * must be valid pointers. 61 * 62 * It does not return a value 63 */ 64 void __thermal_zone_set_trips(struct thermal_zone_device *tz) 65 { 66 const struct thermal_trip *trip; 67 int low = -INT_MAX, high = INT_MAX; 68 int ret; 69 70 lockdep_assert_held(&tz->lock); 71 72 if (!tz->ops.set_trips) 73 return; 74 75 for_each_trip(tz, trip) { 76 int trip_low; 77 78 trip_low = trip->temperature - trip->hysteresis; 79 80 if (trip_low < tz->temperature && trip_low > low) 81 low = trip_low; 82 83 if (trip->temperature > tz->temperature && 84 trip->temperature < high) 85 high = trip->temperature; 86 } 87 88 /* No need to change trip points */ 89 if (tz->prev_low_trip == low && tz->prev_high_trip == high) 90 return; 91 92 tz->prev_low_trip = low; 93 tz->prev_high_trip = high; 94 95 dev_dbg(&tz->device, 96 "new temperature boundaries: %d < x < %d\n", low, high); 97 98 /* 99 * Set a temperature window. When this window is left the driver 100 * must inform the thermal core via thermal_zone_device_update. 101 */ 102 ret = tz->ops.set_trips(tz, low, high); 103 if (ret) 104 dev_err(&tz->device, "Failed to set trips: %d\n", ret); 105 } 106 107 int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, 108 struct thermal_trip *trip) 109 { 110 if (!tz || trip_id < 0 || trip_id >= tz->num_trips || !trip) 111 return -EINVAL; 112 113 *trip = tz->trips[trip_id]; 114 return 0; 115 } 116 EXPORT_SYMBOL_GPL(__thermal_zone_get_trip); 117 118 int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, 119 struct thermal_trip *trip) 120 { 121 int ret; 122 123 mutex_lock(&tz->lock); 124 ret = __thermal_zone_get_trip(tz, trip_id, trip); 125 mutex_unlock(&tz->lock); 126 127 return ret; 128 } 129 EXPORT_SYMBOL_GPL(thermal_zone_get_trip); 130 131 int thermal_zone_trip_id(const struct thermal_zone_device *tz, 132 const struct thermal_trip *trip) 133 { 134 /* 135 * Assume the trip to be located within the bounds of the thermal 136 * zone's trips[] table. 137 */ 138 return trip - tz->trips; 139 } 140 void thermal_zone_trip_updated(struct thermal_zone_device *tz, 141 const struct thermal_trip *trip) 142 { 143 thermal_notify_tz_trip_change(tz, trip); 144 __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); 145 } 146 147 void thermal_zone_set_trip_temp(struct thermal_zone_device *tz, 148 struct thermal_trip *trip, int temp) 149 { 150 if (trip->temperature == temp) 151 return; 152 153 trip->temperature = temp; 154 thermal_notify_tz_trip_change(tz, trip); 155 } 156 EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp); 157