--- /dev/null
+/*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");