Commit a92bab89 authored by Viresh Kumar's avatar Viresh Kumar Committed by Eduardo Valentin

of: thermal: Allow multiple devices to share cooling map

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. The trip
point and contribution value is shared by multiple cooling devices now
and so a new structure is created, struct __thermal_cooling_bind_param,
which represents a cooling device and its min/max states and the
existing struct __thermal_bind_params now contains an array of this new
cooling device structure.

Tested on Hikey960.
Signed-off-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: default avatarEduardo Valentin <edubezval@gmail.com>
parent f1599f9e
...@@ -19,22 +19,33 @@ ...@@ -19,22 +19,33 @@
/*** Private data structures to represent thermal device tree data ***/ /*** 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 * @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 * @min: minimum cooling state used at this trip point
* @max: maximum 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; struct device_node *cooling_device;
unsigned int trip_id;
unsigned int usage;
unsigned long min; unsigned long min;
unsigned long max; 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 * struct __thermal_zone - internal representation of a thermal zone
* @mode: current thermal zone device mode (enabled/disabled) * @mode: current thermal zone device mode (enabled/disabled)
...@@ -192,25 +203,31 @@ static int of_thermal_bind(struct thermal_zone_device *thermal, ...@@ -192,25 +203,31 @@ static int of_thermal_bind(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev) struct thermal_cooling_device *cdev)
{ {
struct __thermal_zone *data = thermal->devdata; 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)) if (!data || IS_ERR(data))
return -ENODEV; return -ENODEV;
/* find where to bind */ /* find where to bind */
for (i = 0; i < data->num_tbps; i++) { 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) { for (j = 0; j < tbp->count; j++) {
int ret; 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->trip_id, cdev,
tbp->max, tcbp->max,
tbp->min, tcbp->min,
tbp->usage); tbp->usage);
if (ret) if (ret)
return ret; return ret;
}
} }
} }
...@@ -221,22 +238,28 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal, ...@@ -221,22 +238,28 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev) struct thermal_cooling_device *cdev)
{ {
struct __thermal_zone *data = thermal->devdata; 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)) if (!data || IS_ERR(data))
return -ENODEV; return -ENODEV;
/* find where to unbind */ /* find where to unbind */
for (i = 0; i < data->num_tbps; i++) { 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) { if (tcbp->cooling_device == cdev->np) {
int ret; int ret;
ret = thermal_zone_unbind_cooling_device(thermal, ret = thermal_zone_unbind_cooling_device(thermal,
tbp->trip_id, cdev); tbp->trip_id, cdev);
if (ret) if (ret)
return ret; return ret;
}
} }
} }
...@@ -652,8 +675,9 @@ static int thermal_of_populate_bind_params(struct device_node *np, ...@@ -652,8 +675,9 @@ static int thermal_of_populate_bind_params(struct device_node *np,
int ntrips) int ntrips)
{ {
struct of_phandle_args cooling_spec; struct of_phandle_args cooling_spec;
struct __thermal_cooling_bind_param *__tcbp;
struct device_node *trip; struct device_node *trip;
int ret, i; int ret, i, count;
u32 prop; u32 prop;
/* Default weight. Usage is optional */ /* Default weight. Usage is optional */
...@@ -680,20 +704,44 @@ static int thermal_of_populate_bind_params(struct device_node *np, ...@@ -680,20 +704,44 @@ static int thermal_of_populate_bind_params(struct device_node *np,
goto end; goto end;
} }
ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells", count = of_count_phandle_with_args(np, "cooling-device",
0, &cooling_spec); "#cooling-cells");
if (ret < 0) { if (!count) {
pr_err("missing cooling_device property\n"); pr_err("Add a cooling_device property with at least one device\n");
goto end; goto end;
} }
__tbp->cooling_device = cooling_spec.np;
if (cooling_spec.args_count >= 2) { /* at least min and max */ __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL);
__tbp->min = cooling_spec.args[0]; if (!__tcbp)
__tbp->max = cooling_spec.args[1]; goto end;
} else {
pr_err("wrong reference to cooling device, missing limits\n"); 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: end:
of_node_put(trip); of_node_put(trip);
...@@ -900,8 +948,16 @@ __init *thermal_of_build_thermal_zone(struct device_node *np) ...@@ -900,8 +948,16 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
return tz; return tz;
free_tbps: free_tbps:
for (i = i - 1; i >= 0; i--) for (i = i - 1; i >= 0; i--) {
of_node_put(tz->tbps[i].cooling_device); 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); kfree(tz->tbps);
free_trips: free_trips:
for (i = 0; i < tz->ntrips; i++) for (i = 0; i < tz->ntrips; i++)
...@@ -917,10 +973,18 @@ __init *thermal_of_build_thermal_zone(struct device_node *np) ...@@ -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) 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); kfree(tz->tbps);
for (i = 0; i < tz->ntrips; i++) for (i = 0; i < tz->ntrips; i++)
of_node_put(tz->trips[i].np); of_node_put(tz->trips[i].np);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment