static inline
void print_bind_err_msg(struct thermal_zone_device *tz,
+ const struct thermal_trip *trip,
struct thermal_cooling_device *cdev, int ret)
{
+ if (trip) {
+ dev_err(&tz->device, "binding cdev %s to trip %d failed: %d\n",
+ cdev->type, thermal_zone_trip_id(tz, trip), ret);
+ return;
+ }
+
dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
tz->type, cdev->type, ret);
}
+static void thermal_zone_cdev_binding(struct thermal_zone_device *tz,
+ struct thermal_cooling_device *cdev)
+{
+ struct thermal_trip_desc *td;
+ int ret;
+
+ /*
+ * Old-style binding. The .bind() callback is expected to call
+ * thermal_bind_cdev_to_trip() under the thermal zone lock.
+ */
+ if (tz->ops.bind) {
+ ret = tz->ops.bind(tz, cdev);
+ if (ret)
+ print_bind_err_msg(tz, NULL, cdev, ret);
+
+ return;
+ }
+
+ if (!tz->ops.should_bind)
+ return;
+
+ mutex_lock(&tz->lock);
+
+ for_each_trip_desc(tz, td) {
+ struct thermal_trip *trip = &td->trip;
+ struct cooling_spec c = {
+ .upper = THERMAL_NO_LIMIT,
+ .lower = THERMAL_NO_LIMIT,
+ .weight = THERMAL_WEIGHT_DEFAULT
+ };
+
+ if (tz->ops.should_bind(tz, trip, cdev, &c)) {
+ ret = thermal_bind_cdev_to_trip(tz, trip, cdev, c.upper,
+ c.lower, c.weight);
+ if (ret)
+ print_bind_err_msg(tz, trip, cdev, ret);
+ }
+ }
+
+ mutex_unlock(&tz->lock);
+}
+
/**
* __thermal_cooling_device_register() - register a new thermal cooling device
* @np: a pointer to a device tree node.
list_add(&cdev->node, &thermal_cdev_list);
/* Update binding information for 'this' new cdev */
- list_for_each_entry(pos, &thermal_tz_list, node) {
- if (pos->ops.bind) {
- ret = pos->ops.bind(pos, cdev);
- if (ret)
- print_bind_err_msg(pos, cdev, ret);
- }
- }
+ list_for_each_entry(pos, &thermal_tz_list, node)
+ thermal_zone_cdev_binding(pos, cdev);
list_for_each_entry(pos, &thermal_tz_list, node)
if (atomic_cmpxchg(&pos->need_update, 1, 0))
}
EXPORT_SYMBOL_GPL(thermal_cooling_device_update);
+static void thermal_zone_cdev_unbinding(struct thermal_zone_device *tz,
+ struct thermal_cooling_device *cdev)
+{
+ struct thermal_trip_desc *td;
+
+ /*
+ * Old-style unbinding. The .unbind callback is expected to call
+ * thermal_unbind_cdev_from_trip() under the thermal zone lock.
+ */
+ if (tz->ops.unbind) {
+ tz->ops.unbind(tz, cdev);
+ return;
+ }
+
+ mutex_lock(&tz->lock);
+
+ for_each_trip_desc(tz, td)
+ thermal_unbind_cdev_from_trip(tz, &td->trip, cdev);
+
+ mutex_unlock(&tz->lock);
+}
+
/**
* thermal_cooling_device_unregister - removes a thermal cooling device
* @cdev: the thermal cooling device to remove.
list_del(&cdev->node);
/* Unbind all thermal zones associated with 'this' cdev */
- list_for_each_entry(tz, &thermal_tz_list, node) {
- if (tz->ops.unbind)
- tz->ops.unbind(tz, cdev);
- }
+ list_for_each_entry(tz, &thermal_tz_list, node)
+ thermal_zone_cdev_unbinding(tz, cdev);
mutex_unlock(&thermal_list_lock);
unsigned int polling_delay)
{
const struct thermal_trip *trip = trips;
+ struct thermal_cooling_device *cdev;
struct thermal_zone_device *tz;
struct thermal_trip_desc *td;
int id;
return ERR_PTR(-EINVAL);
}
- if (!ops || !ops->get_temp) {
- pr_err("Thermal zone device ops not defined\n");
+ if (!ops || !ops->get_temp || (ops->should_bind && ops->bind) ||
+ (ops->should_bind && ops->unbind)) {
+ pr_err("Thermal zone device ops not defined or invalid\n");
return ERR_PTR(-EINVAL);
}
mutex_unlock(&tz->lock);
/* Bind cooling devices for this zone */
- if (tz->ops.bind) {
- struct thermal_cooling_device *cdev;
-
- list_for_each_entry(cdev, &thermal_cdev_list, node) {
- result = tz->ops.bind(tz, cdev);
- if (result)
- print_bind_err_msg(tz, cdev, result);
- }
- }
+ list_for_each_entry(cdev, &thermal_cdev_list, node)
+ thermal_zone_cdev_binding(tz, cdev);
mutex_unlock(&thermal_list_lock);
/* Unbind all cdevs associated with 'this' thermal zone */
list_for_each_entry(cdev, &thermal_cdev_list, node)
- if (tz->ops.unbind)
- tz->ops.unbind(tz, cdev);
+ thermal_zone_cdev_unbinding(tz, cdev);
mutex_unlock(&thermal_list_lock);