@@ -136,7 +136,8 @@ static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *n
return ERR_PTR(ret);
}
-static struct device_node *of_thermal_zone_find(struct device_node *sensor, int id)
+static struct device_node *of_thermal_zone_find(struct device_node *sensor,
+ int id, int *index)
{
struct device_node *np, *tz;
struct of_phandle_args sensor_specs;
@@ -179,6 +180,8 @@ static struct device_node *of_thermal_zone_find(struct device_node *sensor, int
if ((sensor == sensor_specs.np) && id == (sensor_specs.args_count ?
sensor_specs.args[0] : 0)) {
pr_debug("sensor %pOFn id=%d belongs to %pOFn\n", sensor, id, child);
+ /* return index only if multiple entries exist */
+ *index = (count > 1) ? i : -1;
tz = no_free_ptr(child);
goto out;
}
@@ -213,11 +216,10 @@ static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdel
return 0;
}
-static void thermal_of_parameters_init(struct device_node *np,
+static void thermal_of_parameters_init(struct device_node *np, int index,
struct thermal_zone_params *tzp)
{
- int coef[2];
- int ncoef = ARRAY_SIZE(coef);
+ int ncoef, count;
int prop, ret;
tzp->no_hwmon = true;
@@ -226,18 +228,46 @@ static void thermal_of_parameters_init(struct device_node *np,
tzp->sustainable_power = prop;
/*
- * For now, the thermal framework supports only one sensor per
- * thermal zone. Thus, we are considering only the first two
- * values as slope and offset.
+ * If only one sensor is specified in "thermal-sensors" (index == -1)
+ * then only the first two "coefficients" values are considered, and
+ * used as slope and offset (legacy interpretation).
+ *
+ * If /thermal-sensors" contains more than one sensor then index
+ * contains a positive value indicating the "coefficients" value of
+ * interest. The listed sensors are meant to be aggregated and the
+ * provided coefficients represent the relative weight among those
+ * sensors. The slope field is used for that purpose while the offset
+ * is always 0.
*/
- ret = of_property_read_u32_array(np, "coefficients", coef, ncoef);
- if (ret) {
- coef[0] = 1;
- coef[1] = 0;
+ tzp->slope = 1;
+ tzp->offset = 0;
+ if (index == -1) {
+ int coef[2];
+
+ ncoef = ARRAY_SIZE(coef);
+ ret = of_property_read_u32_array(np, "coefficients", coef, ncoef);
+ if (!ret) {
+ tzp->slope = coef[0];
+ tzp->offset = coef[1];
+ }
+ } else {
+ ncoef = of_property_count_u32_elems(np, "coefficients");
+ if (ncoef > 0) {
+ count = of_count_phandle_with_args(np, "thermal-sensors",
+ "#thermal-sensor-cells");
+ if (ncoef != count) {
+ pr_err("%pOFn: sensors and coefficients mismatch\n", np);
+ } else {
+ int *coef = kmalloc(sizeof(*coef) * (index + 1),
+ GFP_KERNEL);
+ if (coef &&
+ of_property_read_u32_array(np, "coefficients",
+ coef, (index + 1)) == 0)
+ tzp->slope = coef[index];
+ kfree(coef);
+ }
+ }
}
-
- tzp->slope = coef[0];
- tzp->offset = coef[1];
}
static struct device_node *thermal_of_zone_get_by_name(struct thermal_zone_device *tz)
@@ -386,9 +416,10 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
const char *action;
int delay, pdelay;
int ntrips;
+ int index;
int ret;
- np = of_thermal_zone_find(sensor, id);
+ np = of_thermal_zone_find(sensor, id, &index);
if (IS_ERR(np)) {
if (PTR_ERR(np) != -ENODEV)
pr_err("Failed to find thermal zone for %pOFn id=%d\n", sensor, id);
@@ -411,7 +442,7 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
goto out_kfree_trips;
}
- thermal_of_parameters_init(np, &tzp);
+ thermal_of_parameters_init(np, index, &tzp);
of_ops.should_bind = thermal_of_should_bind;