Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux...
[muen/linux.git] / drivers / thermal / of-thermal.c
index 4f28165592056d5ec90309c5bff737f5ba66ea0b..4bfdb4a1e47d4fa1f7527c7cf16fd82872e8118a 100644 (file)
 /***   Private data structures to represent thermal device tree data ***/
 
 /**
- * struct __thermal_bind_param - a match between trip and cooling device
+ * struct __thermal_cooling_bind_param - a cooling device for a trip point
  * @cooling_device: a pointer to identify the referred cooling device
- * @trip_id: the trip point index
- * @usage: the percentage (from 0 to 100) of cooling contribution
  * @min: minimum cooling state used at this trip point
  * @max: maximum cooling state used at this trip point
  */
 
-struct __thermal_bind_params {
+struct __thermal_cooling_bind_param {
        struct device_node *cooling_device;
-       unsigned int trip_id;
-       unsigned int usage;
        unsigned long min;
        unsigned long max;
 };
 
+/**
+ * struct __thermal_bind_param - a match between trip and cooling device
+ * @tcbp: a pointer to an array of cooling devices
+ * @count: number of elements in array
+ * @trip_id: the trip point index
+ * @usage: the percentage (from 0 to 100) of cooling contribution
+ */
+
+struct __thermal_bind_params {
+       struct __thermal_cooling_bind_param *tcbp;
+       unsigned int count;
+       unsigned int trip_id;
+       unsigned int usage;
+};
+
 /**
  * struct __thermal_zone - internal representation of a thermal zone
  * @mode: current thermal zone device mode (enabled/disabled)
@@ -192,25 +203,31 @@ static int of_thermal_bind(struct thermal_zone_device *thermal,
                           struct thermal_cooling_device *cdev)
 {
        struct __thermal_zone *data = thermal->devdata;
-       int i;
+       struct __thermal_bind_params *tbp;
+       struct __thermal_cooling_bind_param *tcbp;
+       int i, j;
 
        if (!data || IS_ERR(data))
                return -ENODEV;
 
        /* find where to bind */
        for (i = 0; i < data->num_tbps; i++) {
-               struct __thermal_bind_params *tbp = data->tbps + i;
+               tbp = data->tbps + i;
 
-               if (tbp->cooling_device == cdev->np) {
-                       int ret;
+               for (j = 0; j < tbp->count; j++) {
+                       tcbp = tbp->tcbp + j;
 
-                       ret = thermal_zone_bind_cooling_device(thermal,
+                       if (tcbp->cooling_device == cdev->np) {
+                               int ret;
+
+                               ret = thermal_zone_bind_cooling_device(thermal,
                                                tbp->trip_id, cdev,
-                                               tbp->max,
-                                               tbp->min,
+                                               tcbp->max,
+                                               tcbp->min,
                                                tbp->usage);
-                       if (ret)
-                               return ret;
+                               if (ret)
+                                       return ret;
+                       }
                }
        }
 
@@ -221,22 +238,28 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
                             struct thermal_cooling_device *cdev)
 {
        struct __thermal_zone *data = thermal->devdata;
-       int i;
+       struct __thermal_bind_params *tbp;
+       struct __thermal_cooling_bind_param *tcbp;
+       int i, j;
 
        if (!data || IS_ERR(data))
                return -ENODEV;
 
        /* find where to unbind */
        for (i = 0; i < data->num_tbps; i++) {
-               struct __thermal_bind_params *tbp = data->tbps + i;
+               tbp = data->tbps + i;
+
+               for (j = 0; j < tbp->count; j++) {
+                       tcbp = tbp->tcbp + j;
 
-               if (tbp->cooling_device == cdev->np) {
-                       int ret;
+                       if (tcbp->cooling_device == cdev->np) {
+                               int ret;
 
-                       ret = thermal_zone_unbind_cooling_device(thermal,
-                                               tbp->trip_id, cdev);
-                       if (ret)
-                               return ret;
+                               ret = thermal_zone_unbind_cooling_device(thermal,
+                                                       tbp->trip_id, cdev);
+                               if (ret)
+                                       return ret;
+                       }
                }
        }
 
@@ -486,8 +509,8 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
                if (sensor_specs.args_count >= 1) {
                        id = sensor_specs.args[0];
                        WARN(sensor_specs.args_count > 1,
-                            "%s: too many cells in sensor specifier %d\n",
-                            sensor_specs.np->name, sensor_specs.args_count);
+                            "%pOFn: too many cells in sensor specifier %d\n",
+                            sensor_specs.np, sensor_specs.args_count);
                } else {
                        id = 0;
                }
@@ -655,8 +678,9 @@ static int thermal_of_populate_bind_params(struct device_node *np,
                                           int ntrips)
 {
        struct of_phandle_args cooling_spec;
+       struct __thermal_cooling_bind_param *__tcbp;
        struct device_node *trip;
-       int ret, i;
+       int ret, i, count;
        u32 prop;
 
        /* Default weight. Usage is optional */
@@ -683,20 +707,44 @@ static int thermal_of_populate_bind_params(struct device_node *np,
                goto end;
        }
 
-       ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells",
-                                        0, &cooling_spec);
-       if (ret < 0) {
-               pr_err("missing cooling_device property\n");
+       count = of_count_phandle_with_args(np, "cooling-device",
+                                          "#cooling-cells");
+       if (!count) {
+               pr_err("Add a cooling_device property with at least one device\n");
                goto end;
        }
-       __tbp->cooling_device = cooling_spec.np;
-       if (cooling_spec.args_count >= 2) { /* at least min and max */
-               __tbp->min = cooling_spec.args[0];
-               __tbp->max = cooling_spec.args[1];
-       } else {
-               pr_err("wrong reference to cooling device, missing limits\n");
+
+       __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL);
+       if (!__tcbp)
+               goto end;
+
+       for (i = 0; i < count; i++) {
+               ret = of_parse_phandle_with_args(np, "cooling-device",
+                               "#cooling-cells", i, &cooling_spec);
+               if (ret < 0) {
+                       pr_err("Invalid cooling-device entry\n");
+                       goto free_tcbp;
+               }
+
+               __tcbp[i].cooling_device = cooling_spec.np;
+
+               if (cooling_spec.args_count >= 2) { /* at least min and max */
+                       __tcbp[i].min = cooling_spec.args[0];
+                       __tcbp[i].max = cooling_spec.args[1];
+               } else {
+                       pr_err("wrong reference to cooling device, missing limits\n");
+               }
        }
 
+       __tbp->tcbp = __tcbp;
+       __tbp->count = count;
+
+       goto end;
+
+free_tcbp:
+       for (i = i - 1; i >= 0; i--)
+               of_node_put(__tcbp[i].cooling_device);
+       kfree(__tcbp);
 end:
        of_node_put(trip);
 
@@ -903,8 +951,16 @@ finish:
        return tz;
 
 free_tbps:
-       for (i = i - 1; i >= 0; i--)
-               of_node_put(tz->tbps[i].cooling_device);
+       for (i = i - 1; i >= 0; i--) {
+               struct __thermal_bind_params *tbp = tz->tbps + i;
+               int j;
+
+               for (j = 0; j < tbp->count; j++)
+                       of_node_put(tbp->tcbp[j].cooling_device);
+
+               kfree(tbp->tcbp);
+       }
+
        kfree(tz->tbps);
 free_trips:
        for (i = 0; i < tz->ntrips; i++)
@@ -920,10 +976,18 @@ free_tz:
 
 static inline void of_thermal_free_zone(struct __thermal_zone *tz)
 {
-       int i;
+       struct __thermal_bind_params *tbp;
+       int i, j;
+
+       for (i = 0; i < tz->num_tbps; i++) {
+               tbp = tz->tbps + i;
+
+               for (j = 0; j < tbp->count; j++)
+                       of_node_put(tbp->tcbp[j].cooling_device);
+
+               kfree(tbp->tcbp);
+       }
 
-       for (i = 0; i < tz->num_tbps; i++)
-               of_node_put(tz->tbps[i].cooling_device);
        kfree(tz->tbps);
        for (i = 0; i < tz->ntrips; i++)
                of_node_put(tz->trips[i].np);
@@ -963,8 +1027,8 @@ int __init of_parse_thermal_zones(void)
 
                tz = thermal_of_build_thermal_zone(child);
                if (IS_ERR(tz)) {
-                       pr_err("failed to build thermal zone %s: %ld\n",
-                              child->name,
+                       pr_err("failed to build thermal zone %pOFn: %ld\n",
+                              child,
                               PTR_ERR(tz));
                        continue;
                }
@@ -998,7 +1062,7 @@ int __init of_parse_thermal_zones(void)
                                                    tz->passive_delay,
                                                    tz->polling_delay);
                if (IS_ERR(zone)) {
-                       pr_err("Failed to build %s zone %ld\n", child->name,
+                       pr_err("Failed to build %pOFn zone %ld\n", child,
                               PTR_ERR(zone));
                        kfree(tzp);
                        kfree(ops);