A cooling map entry may now contain a list of phandles and their
arguments representing multiple devices which share the trip point.

This patch updates the thermal OF core to parse them properly.

Tested on Hikey960.

Signed-off-by: Viresh Kumar <viresh.ku...@linaro.org>
---
This is a follow up patch to the DT bindings patchset:

https://lkml.kernel.org/r/cover.1530766981.git.viresh.ku...@linaro.org

 drivers/thermal/of-thermal.c | 140 +++++++++++++++++++++++++----------
 1 file changed, 102 insertions(+), 38 deletions(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 977a8307fbb1..79c06c4c861b 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -19,22 +19,33 @@
 /***   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;
+                       }
                }
        }
 
@@ -652,8 +675,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 */
@@ -680,20 +704,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) {
+       count = of_count_phandle_with_args(np, "cooling-device",
+                                          "#cooling-cells");
+       if (!count) {
                pr_err("missing cooling_device property\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("missing cooling_device property\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);
 
@@ -900,8 +948,16 @@ __init *thermal_of_build_thermal_zone(struct device_node 
*np)
        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++)
@@ -917,10 +973,18 @@ __init *thermal_of_build_thermal_zone(struct device_node 
*np)
 
 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);
-- 
2.18.0.rc1.242.g61856ae69a2c

Reply via email to