thermal: add virtual temperature sensor
authorLukasz Luba <l.luba@partner.samsung.com>
Tue, 14 Aug 2018 15:48:00 +0000 (17:48 +0200)
committerLukasz Luba <l.luba@partner.samsung.com>
Fri, 17 May 2019 07:15:37 +0000 (09:15 +0200)
The new type of sensor allows to calculate temperature
of thermal zone container. It relays on real thermal zones
temperature and provides basic weighted avg algorithm.

Signed-off-by: Lukasz Luba <l.luba@partner.samsung.com>
drivers/thermal/Makefile
drivers/thermal/virt_tsens.c [new file with mode: 0644]

index 610344eb3e03378c69d56f60178ff8222f5d0435..c0d29120379a4abf6357b5999844684067471066 100644 (file)
@@ -27,6 +27,8 @@ thermal_sys-$(CONFIG_CLOCK_THERMAL)   += clock_cooling.o
 # devfreq cooling
 thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
 
+obj-y  += virt_tsens.o
+
 # platform thermal drivers
 obj-y                          += broadcom/
 obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM)     += qcom-spmi-temp-alarm.o
diff --git a/drivers/thermal/virt_tsens.c b/drivers/thermal/virt_tsens.c
new file mode 100644 (file)
index 0000000..59dffea
--- /dev/null
@@ -0,0 +1,126 @@
+/*license */
+
+#define pr_fmt(fmt) "VTSENS: " fmt
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+#include <linux/types.h>
+
+
+
+struct vtsens {
+       struct thermal_zone_device *tzd;
+       struct mutex lock;
+};
+
+static int vtsens_get_temp(void *p, int *temp)
+{
+       struct vtsens *vts = p;
+       struct thermal_zone_device *tzd = vts->tzd;
+       struct thermal_zone_device *tz;
+       int ret = 0;
+       int subtz_temp;
+       int avg_temp = 0;
+       int subzones_capacitance = 0;
+
+       /* We are virtual temp sensor so must relay on real sensors
+        * which are present in subzones. */
+       if (!tzd || !tzd->container)
+               return -EINVAL;
+
+
+       if (list_empty(&tzd->subzones))
+           return -EINVAL;
+
+       list_for_each_entry(tz, &tzd->subzones, subzones) {
+               /* Avoid checking the first entry and prevent from
+                  aggregating containers (circular dependencies, etc.) */
+               if (tz->container)
+                       continue;
+               ret = thermal_zone_get_temp(tz, &subtz_temp);
+               if (ret) {
+                       return ret;
+               }
+               avg_temp += tz->capacitance * subtz_temp;
+               subzones_capacitance += tz->capacitance;
+               /* pr_info("%s, subtz_temp = %d\n", tzd->type, subtz_temp); */
+       }
+
+       if (subzones_capacitance)
+               avg_temp /= subzones_capacitance;
+       else
+               ret = -EINVAL;
+
+       *temp = avg_temp;
+
+       return ret;
+}
+
+static const struct thermal_zone_of_device_ops vtsens_ops = {
+       .get_temp = vtsens_get_temp,
+};
+
+static int vtsens_probe(struct platform_device *pdev)
+{
+       struct vtsens *vts;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       if (!dev || !dev->of_node)
+               return -EINVAL;
+
+       vts = devm_kzalloc(&pdev->dev, sizeof(struct vtsens),
+                           GFP_KERNEL);
+       if (!vts)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, vts);
+       mutex_init(&vts->lock);
+
+       vts->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, vts,
+                                                   &vtsens_ops);
+
+       if (IS_ERR(vts->tzd)) {
+               ret = PTR_ERR(vts->tzd);
+               dev_err(&pdev->dev, "Failed during registration of sensor %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int vtsens_remove(struct platform_device *pdev)
+{
+
+       return 0;
+}
+
+static const struct of_device_id of_virt_tsens_match[] = {
+       { .compatible = "thermal,virt-tsens", },
+       { /* end */ }
+};
+MODULE_DEVICE_TABLE(of, of_virt_tsens_match);
+
+
+static struct platform_driver vtsens_thermal = {
+       .driver = {
+               .name   = "vtsens_thermal",
+               .of_match_table = of_virt_tsens_match,
+       },
+       .probe          = vtsens_probe,
+       .remove         = vtsens_remove,
+};
+module_platform_driver(vtsens_thermal);
+
+MODULE_AUTHOR("Samsung, Inc.");
+MODULE_DESCRIPTION("Virtual temperature sensor driver for agregated thermal zones");
+MODULE_LICENSE("GPL v2");