From: Nicolas Pitre <npitre@xxxxxxxxxxxx> The thermal zone DT binding description says: coefficients: $ref: /schemas/types.yaml#/definitions/uint32-array description: An array of integers containing the coefficients of a linear equation that binds all the sensors listed in this thermal zone. The linear equation used is as follows, z = c0 * x0 + c1 * x1 + ... + c(n-1) * x(n-1) + cn where c0, c1, .., cn are the coefficients. Coefficients default to 1 in case this property is not specified. The coefficients are ordered and are matched with sensors by means of the sensor ID. Additional coefficients are interpreted as constant offset. And the code says: /* * 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. */ Furthermore, only bcm2711_thermal, bcm2835_thermal and ti-soc-thermal use these values. It is not clear how the equation in the bindings documentation should be interpreted especially in the context of multiple sensors and sensor aggregation. Assuming x0..xn are temperature values, coefficients have to be fractional values otherwise the sum won't correspond to a temperature anymore. So this patch interprets those coefficients as per-sensor weight for determining the aggregated temperature value instead. Also, in that context, constant offsets make no sense so they're always set to 0. Because those weights are integer values, they must all be provided otherwise they all default to 1. To preserve backward compatibility, the current behavior is preserved when "thermal-sensors" contains only one entry. The alternative interpretation is applied only when "thermal-sensors" holds multiple entries (which never happened so far). Signed-off-by: Nicolas Pitre <npitre@xxxxxxxxxxxx> --- drivers/thermal/thermal_of.c | 63 +++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c index 07e0989716..b8ddd41247 100644 --- a/drivers/thermal/thermal_of.c +++ b/drivers/thermal/thermal_of.c @@ -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; -- 2.47.0