From nobody Thu Dec 25 12:40:13 2025 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 26054145B1D for ; Thu, 13 Jun 2024 13:24:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718285063; cv=none; b=O/yIfBbTbyO2NVURzxJDg4DNuagwFTaJ0Wwf130Lpap4xmIEfTQ/xHCfnsTA3Y8+lje50pnawDz0JBBO8Hbs8iqTjVAKO/Y8SHjTvmehTz4iZ0/eRbcbH2+bAXP0/YUibqSWrmHosp2MHXx6N5L/oFb8FLVajjgzdwWxgkScMxY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718285063; c=relaxed/simple; bh=LpbziCjZRkzrPCbzYtUAQhYRDTw/5cNCLTZgMC5mxrE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bG2B01+jfFWhsIa2V8R+eSHQqvgSwWa14rlpuKUkYacqdXICnA2lr0L11KieDAH5wfpoIqJ79hFhgwbcHCBUe1uc5H1CyegQOCPHgld57VyPZ+qlttzDvHK4t4oRqPCZ0tn9UB40ykCG220+7V+B+8jhoP4/JVkUsggRKAbDTEA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=v7CYwVN3; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="v7CYwVN3" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-421bb51d81aso8369535e9.3 for ; Thu, 13 Jun 2024 06:24:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1718285059; x=1718889859; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Tya0ITp4z4S3hnZL7iK4UAV9x+Mi7A2TRjTzUlOjL/8=; b=v7CYwVN3TCuTZjXV5IVE04Lu+ji9UjYw3OCp9bxeN2OhWTGDa2imrnOQ5gqlLUmXIX 6CCAXqtuL3Zz7NeomSI4TCXFCgS9ua/6OjkLeJWwEen9/+y1KBikWVEadFxjtV/alJlT Yixy8aOxxjJZoWzKF7D60kQt2zyZ+jYCi3/sv2ck/m3ROfzqQvZyLw9aZA3eSzDSflDJ 8CO9ZGU5LbSjncOAhZzQbr9sF4zERoV7HBPYaohRFpYpNdDNJaYD5nZou1vSbOqg+yq/ uGpUyNYkCJ3oJ01Ej+RKGv1ZlE7gmtyxXAkpEFUJbn4rsISKy78Fqi9+4UawEwlD+hLt ErBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718285059; x=1718889859; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Tya0ITp4z4S3hnZL7iK4UAV9x+Mi7A2TRjTzUlOjL/8=; b=Sdu0N3wEhXTLHPvL7pVhTy49pI9ZPClFaFwTnGgb+q5WYcnYKKWqEPEiwQyVgrY1v3 Hk0g+54ZxqYZp329D98BmreqjehHJsDvdqeJRbwJ8TMG/8ua9RP5ufMaXQQ3CrNIspH0 ZsD66Owzn4h60Ap6caYVboa2BJsJyPSnfdSjTvZIT5nknagk1PjtfSrg9naEp3Wc2I9Q a6ZJ9MmfvGJ+WiHchDDKfmpIGlyudYNOMHkZ7HOMVSPPthzxuBDpEfg76tdr1Y9Xn2PW yBZArQWESpsc0JT5b5kIpUtu/47hODzS9b8HRzVvd0HJli8EpTuUu60ZMwsoYHsq+eVb pzAw== X-Forwarded-Encrypted: i=1; AJvYcCXLt9zGMJYUHzxsfdH4Lzx1/2/E+Xc5LZe2Jy4A5J6/4KeFkDP+7QNzPGoE/XV8pjC5bua5R6ofUjkB4tKYvAW/edLwIbiAqYOx+Mpr X-Gm-Message-State: AOJu0YyCwpo59mVJJU0wdg8ZV8/DnA5PPb2Sry/z4SPwHB4Br3NLFyiq TgNRbseM1hlhSCb08zJmj28Kmy6zIDsoVO3hs4XhBLtIZ6j53yHrrdgptRCZG/w= X-Google-Smtp-Source: AGHT+IGbVJk/idr4DAbfqDBHeVeUSQXIMINdv853E/IV6oCCF2ifS2Cr4eRXr+Mrg1v3ct8+2iM7VQ== X-Received: by 2002:a05:600c:1f1a:b0:421:7407:d778 with SMTP id 5b1f17b1804b1-422862a7251mr36347485e9.14.1718285059563; Thu, 13 Jun 2024 06:24:19 -0700 (PDT) Received: from blaptop.baylibre (laubervilliers-658-1-213-31.w90-63.abo.wanadoo.fr. [90.63.244.31]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-422f5f33c6esm25086225e9.4.2024.06.13.06.24.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Jun 2024 06:24:18 -0700 (PDT) From: Alexandre Bailon To: rafael@kernel.org, daniel.lezcano@linaro.org, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org Cc: rui.zhang@intel.com, lukasz.luba@arm.com, linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Alexandre Bailon Subject: [PATCH v4 3/4] thermal: Add support of multi sensors to thermal_of Date: Thu, 13 Jun 2024 15:24:09 +0200 Message-ID: <20240613132410.161663-4-abailon@baylibre.com> X-Mailer: git-send-email 2.44.1 In-Reply-To: <20240613132410.161663-1-abailon@baylibre.com> References: <20240613132410.161663-1-abailon@baylibre.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This updates thermal_of to support more than one sensor. If during the registration we find another thermal zone referencing this sensors and some other, then we create the multi sensor thermal zone (if it doesn't exist) and register the sensor to it. Signed-off-by: Alexandre Bailon --- drivers/thermal/thermal_of.c | 250 +++++++++++++++++++++++++++++++++-- 1 file changed, 241 insertions(+), 9 deletions(-) diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c index aa34b6e82e26..fef966557b30 100644 --- a/drivers/thermal/thermal_of.c +++ b/drivers/thermal/thermal_of.c @@ -18,6 +18,8 @@ =20 #include "thermal_core.h" =20 +#define STRLEN_ID (8) + /*** functions parsing device tree nodes ***/ =20 static int of_find_trip_id(struct device_node *np, struct device_node *tri= p) @@ -222,6 +224,77 @@ static struct device_node *of_thermal_zone_find(struct= device_node *sensor, int return tz; } =20 +static int thermal_of_multi_sensor_get_name(struct device_node *sensor, in= t id, + struct device_node *tz, char *name) +{ + struct of_phandle_args sensor_specs; + int count, i; + + tz =3D of_thermal_zone_find(sensor, id); + if (!tz) { + pr_debug("No thermal zones description\n"); + return -ENODEV; + } + + count =3D of_count_phandle_with_args(tz, "thermal-sensors", + "#thermal-sensor-cells"); + if (count <=3D 0) + return count; + + for (i =3D 0; i < count; i++) { + + int ret; + + ret =3D of_parse_phandle_with_args(tz, "thermal-sensors", + "#thermal-sensor-cells", + i, &sensor_specs); + if (ret < 0) { + pr_err("%pOFn: Failed to read thermal-sensors cells: %d\n", tz, ret); + return ret; + } + + if ((sensor =3D=3D sensor_specs.np) && id =3D=3D (sensor_specs.args_coun= t ? + sensor_specs.args[0] : 0)) { + snprintf(name, THERMAL_NAME_LENGTH, "%s%d", tz->name, id); + return 0; + } + } + + return -ENODEV; +} + +static int thermal_of_multi_sensor_get_id(struct device_node *sensor, + struct device_node *tz, int id) +{ + struct of_phandle_args sensor_specs; + int count, i; + + count =3D of_count_phandle_with_args(tz, "thermal-sensors", + "#thermal-sensor-cells"); + if (count <=3D 0) + return 0; + + for (i =3D 0; i < count; i++) { + + int ret; + + ret =3D of_parse_phandle_with_args(tz, "thermal-sensors", + "#thermal-sensor-cells", + i, &sensor_specs); + if (ret < 0) { + pr_err("%pOFn: Failed to read thermal-sensors cells: %d\n", tz, ret); + return 0; + } + + if ((sensor =3D=3D sensor_specs.np) && id =3D=3D (sensor_specs.args_coun= t ? + sensor_specs.args[0] : 0)) { + return i; + } + } + + return -ENODEV; +} + static int thermal_of_monitor_init(struct device_node *np, int *delay, int= *pdelay) { int ret; @@ -281,6 +354,17 @@ static struct device_node *thermal_of_zone_get_by_name= (struct thermal_zone_devic return ERR_PTR(-ENODEV); =20 tz_np =3D of_get_child_by_name(np, tz->type); + if (!tz_np) { + char tmp[THERMAL_NAME_LENGTH]; + char *ptr; + + ptr =3D strrchr(tz->type, '.'); + if (!ptr) + return ERR_PTR(-ENODEV); + + strscpy(tmp, tz->type, (ptr - tz->type) + 1); + tz_np =3D of_get_child_by_name(np, tmp); + } =20 of_node_put(np); =20 @@ -444,10 +528,140 @@ static int thermal_of_unbind(struct thermal_zone_dev= ice *tz, */ static void thermal_of_zone_unregister(struct thermal_zone_device *tz) { + thermal_multi_sensor_unregister(tz); thermal_zone_device_disable(tz); thermal_zone_device_unregister(tz); } =20 +static int thermal_of_multi_sensor_validate_coeff(struct device_node *sens= or, int id, + struct device_node *tz_np) +{ + u32 *coeff; + int ret; + int i; + + int count; + int index; + int offset; + + index =3D thermal_of_multi_sensor_get_id(sensor, tz_np, id); + if (index < 0) + return -ENODEV; + + + count =3D of_count_phandle_with_args(tz_np, + "thermal-sensors", + "#thermal-sensor-cells"); + if (count < 0) + return count; + + coeff =3D kmalloc_array(count, sizeof(*coeff), GFP_KERNEL); + if (!coeff) + return -ENOMEM; + + for (i =3D 0; i < count; i++) { + ret =3D of_property_read_u32_index(tz_np, + "coefficients", + i, coeff + i); + if (ret) + coeff[i] =3D 1; + } + + ret =3D of_property_read_u32_index(tz_np, "coefficients", + count, &offset); + if (ret) + offset =3D 0; + + /* Make sure the coeff and offset won't cause an overflow */ + ret =3D thermal_multi_sensor_validate_coeff(coeff, count, offset); + + kfree(coeff); + + return ret; +} + +static int thermal_of_mutli_sensor_coeff(struct device_node *sensor, int i= d, + struct device_node *tz_np, + u32 *coeff) +{ + int index; + int ret; + + index =3D thermal_of_multi_sensor_get_id(sensor, tz_np, id); + if (index < 0) + return index; + + ret =3D of_property_read_u32_index(tz_np, "coefficients", index, coeff); + if (ret) + *coeff =3D 1; + + return 0; +} + +static struct thermal_zone_device * +thermal_of_register_multi_tz(struct device_node *sensor, int id, struct de= vice_node *np, + const char *type, struct thermal_trip *trips, int num_trips, + void *devdata, struct thermal_zone_device_ops *ops, + const struct thermal_zone_params *tzp, int passive_delay, + int polling_delay) +{ + struct thermal_zone_device *multi_tz, *tz; + char name[THERMAL_NAME_LENGTH]; + u32 coeff; + int ret; + + multi_tz =3D thermal_multi_sensor_find_tz(type); + if (!multi_tz) { + struct thermal_zone_device_ops *multi_ops; + + ret =3D thermal_of_multi_sensor_validate_coeff(sensor, id, np); + if (ret) + return ERR_PTR(ret); + + multi_ops =3D thermal_multi_sensor_alloc_ops(); + if (IS_ERR_OR_NULL(multi_ops)) + return ERR_PTR(PTR_ERR(multi_ops)); + multi_ops->bind =3D thermal_of_bind; + multi_ops->unbind =3D thermal_of_unbind; + + multi_tz =3D thermal_multi_sensor_tz_alloc(type, trips, num_trips, + multi_ops, + passive_delay, polling_delay); + if (IS_ERR_OR_NULL(multi_tz)) { + kfree(multi_ops); + return multi_tz; + } + } + + ret =3D thermal_of_multi_sensor_get_name(sensor, id, np, name); + if (ret) + goto out_release_multi_tz; + + tz =3D thermal_tripless_zone_device_register(name, devdata, ops, tzp); + if (IS_ERR_OR_NULL(tz)) { + ret =3D PTR_ERR(tz); + goto out_release_multi_tz; + } + + ret =3D thermal_of_mutli_sensor_coeff(sensor, id, np, &coeff); + if (ret) + goto out_release_tz; + + ret =3D thermal_multi_sensor_register(multi_tz, tz, coeff); + if (ret) + goto out_release_tz; + + return tz; + +out_release_tz: + thermal_zone_device_unregister(tz); +out_release_multi_tz: + thermal_multi_sensor_tz_free(multi_tz); + + return ERR_PTR(ret); +} + + /** * thermal_of_zone_register - Register a thermal zone with device node * sensor @@ -479,6 +693,7 @@ static struct thermal_zone_device *thermal_of_zone_regi= ster(struct device_node * const char *action; int delay, pdelay; int ntrips; + int count; int ret; =20 np =3D of_thermal_zone_find(sensor, id); @@ -488,10 +703,19 @@ static struct thermal_zone_device *thermal_of_zone_re= gister(struct device_node * return ERR_CAST(np); } =20 - trips =3D thermal_of_trips_init(np, &ntrips); - if (IS_ERR(trips)) { - pr_err("Failed to find trip points for %pOFn id=3D%d\n", sensor, id); - return ERR_CAST(trips); + count =3D of_count_phandle_with_args(np, "thermal-sensors", + "#thermal-sensor-cells"); + if (count <=3D 0) + return ERR_PTR(count); + + /* Only allocate trips if the thermal zone doesn't exist yet */ + if (!thermal_multi_sensor_find_tz(np->name)) { + trips =3D thermal_of_trips_init(np, &ntrips); + if (IS_ERR(trips)) { + pr_err("Failed to find trip points for %pOFn id=3D%d\n", sensor, id); + ret =3D PTR_ERR(trips); + goto out_kfree_trips; + } } =20 ret =3D thermal_of_monitor_init(np, &delay, &pdelay); @@ -502,17 +726,25 @@ static struct thermal_zone_device *thermal_of_zone_re= gister(struct device_node * =20 thermal_of_parameters_init(np, &tzp); =20 - of_ops.bind =3D thermal_of_bind; - of_ops.unbind =3D thermal_of_unbind; + if (count =3D=3D 1) { + of_ops.bind =3D thermal_of_bind; + of_ops.unbind =3D thermal_of_unbind; + } =20 ret =3D of_property_read_string(np, "critical-action", &action); if (!ret) if (!of_ops.critical && !strcasecmp(action, "reboot")) of_ops.critical =3D thermal_zone_device_critical_reboot; =20 - tz =3D thermal_zone_device_register_with_trips(np->name, trips, ntrips, - data, &of_ops, &tzp, - pdelay, delay); + if (count =3D=3D 1) { + tz =3D thermal_zone_device_register_with_trips(np->name, trips, ntrips, + data, &of_ops, &tzp, + pdelay, delay); + } else { + tz =3D thermal_of_register_multi_tz(sensor, id, np, np->name, trips, + ntrips, data, &of_ops, &tzp, + pdelay, delay); + } if (IS_ERR(tz)) { ret =3D PTR_ERR(tz); pr_err("Failed to register thermal zone %pOFn: %d\n", np, ret); --=20 2.44.1