MLK-14972-02 driver: thermal: Add i.MX8QM/QXP thermal support
authorBai Ping <ping.bai@nxp.com>
Tue, 6 Jun 2017 05:53:24 +0000 (13:53 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 20:22:33 +0000 (15:22 -0500)
Add i.MX8QM/QXP thermal driver support.

Signed-off-by: Bai Ping <ping.bai@nxp.com>
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/imx_sc_thermal.c [new file with mode: 0644]

index 9e35c51..8514f47 100644 (file)
@@ -195,6 +195,15 @@ config IMX_THERMAL
          cpufreq is used as the cooling device to throttle CPUs when the
          passive trip is crossed.
 
+config IMX_SC_THERMAL
+       tristate "thermal sensor driver for NXP i.MX8 SoCs"
+       depends on THERMAL_OF && ARCH_MXC_ARM64
+       help
+         Support for Temperature Monitor (TEMPMON) found on NXP i.MX SOCs
+         with system controller.
+         cpufreq is used as the cooling device to throttle CPUs when the
+         passive trip is crossed.
+
 config MAX77620_THERMAL
        tristate "Temperature sensor driver for Maxim MAX77620 PMIC"
        depends on MFD_MAX77620
index 842efac..f70b7cf 100644 (file)
@@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL)  += db8500_thermal.o
 obj-$(CONFIG_ARMADA_THERMAL)   += armada_thermal.o
 obj-$(CONFIG_TANGO_THERMAL)    += tango_thermal.o
 obj-$(CONFIG_IMX_THERMAL)      += imx_thermal.o
+obj-$(CONFIG_IMX_SC_THERMAL)   += imx_sc_thermal.o
 obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o
 obj-$(CONFIG_QORIQ_THERMAL)    += qoriq_thermal.o
 obj-$(CONFIG_DEVICE_THERMAL)   += device_cooling.o
diff --git a/drivers/thermal/imx_sc_thermal.c b/drivers/thermal/imx_sc_thermal.c
new file mode 100644 (file)
index 0000000..90c5c25
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2017 NXP.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+#include <soc/imx8/sc/sci.h>
+
+struct imx_sc_sensor {
+       struct thermal_zone_device *tzd;
+       sc_rsrc_t hw_id;
+};
+
+struct imx_sc_tsens_device {
+       u32 sensor_num;
+       struct imx_sc_sensor sensor[0];
+};
+
+/* The driver support 1 passive trip point and 1 critical trip point */
+enum imx_thermal_trip {
+       IMX_TRIP_PASSIVE,
+       IMX_TRIP_CRITICAL,
+       IMX_TRIP_NUM,
+};
+
+static const sc_rsrc_t imx8qm_sensor_hw_id[] = {
+       SC_R_A53, SC_R_A72, SC_R_GPU_0_PID0, SC_R_GPU_1_PID0,
+       SC_R_DRC_0, SC_R_DRC_1, SC_R_VPU_PID0, SC_R_PMIC_0,
+       SC_R_PMIC_1, SC_R_PMIC_2,
+};
+
+static const sc_rsrc_t imx8qxp_sensor_hw_id[] = {
+       SC_R_DRC_0,
+};
+
+const int *sensor_hw_id;
+sc_ipc_t tsens_ipcHandle;
+
+static int imx_sc_tsens_get_temp(void *data, int *temp)
+{
+       struct imx_sc_sensor *sensor = data;
+       sc_err_t sciErr;
+       int16_t celsius;
+       int8_t tenths;
+
+       sciErr = sc_misc_get_temp(tsens_ipcHandle, sensor->hw_id,
+                       SC_C_TEMP, &celsius, &tenths);
+       /*
+        * if the SS power domain is down, read temp will fail, so
+        * we can return the temp of A53 CPU domain instead.
+        */
+       if (sciErr != SC_ERR_NONE) {
+               sciErr = sc_misc_get_temp(tsens_ipcHandle, sensor_hw_id[0],
+                               SC_C_TEMP, &celsius, &tenths);
+               if (sciErr != SC_ERR_NONE) {
+                       pr_err("read temp sensor:%d failed\n", sensor->hw_id);
+                       return -EINVAL;
+               }
+       }
+       *temp = celsius * 1000 + tenths;
+
+       return 0;
+}
+
+static int imx_sc_tsens_get_trend(void *p, int trip, enum thermal_trend *trend)
+{
+       return 0;
+}
+
+
+static const struct thermal_zone_of_device_ops imx_sc_tsens_ops = {
+       .get_temp = imx_sc_tsens_get_temp,
+       .get_trend = imx_sc_tsens_get_trend,
+};
+
+static const struct of_device_id imx_sc_tsens_table[] = {
+       { .compatible = "nxp,imx8qm-sc-tsens", .data = &imx8qm_sensor_hw_id, },
+       { .compatible = "nxp,imx8qxp-sc-tsens", .data = &imx8qxp_sensor_hw_id, },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, imx_sc_tsens_table);
+
+static int imx_sc_tsens_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct imx_sc_tsens_device *tsens_dev;
+       struct imx_sc_sensor *sensor;
+       struct thermal_zone_device *tzd;
+       sc_err_t sciErr;
+       uint32_t mu_id;
+       u32 tsens_num;
+       int ret, sensor_id;
+
+       sciErr = sc_ipc_getMuID(&mu_id);
+       if (sciErr != SC_ERR_NONE) {
+               dev_err(&pdev->dev, "Can not get the mu id: %d\n", sciErr);
+               return -ENODEV;
+       };
+
+       sciErr = sc_ipc_open(&tsens_ipcHandle, mu_id);
+       if (sciErr != SC_ERR_NONE) {
+               dev_err(&pdev->dev, "open mu channel failed: %d\n", sciErr);
+               return -EINVAL;
+       };
+       sensor_hw_id = of_device_get_match_data(&pdev->dev);
+
+       /* get the temp sensor number from device node */
+       of_property_read_u32(np, "tsens-num", &tsens_num);
+       if (!tsens_num) {
+               dev_err(&pdev->dev, "no temp sensor number provided!\n");
+               return -EINVAL;
+       }
+
+       tsens_dev = devm_kzalloc(&pdev->dev, sizeof(*tsens_dev) +
+                                tsens_num * sizeof(*sensor), GFP_KERNEL);
+       if (!tsens_dev)
+               return -ENOMEM;
+
+       tsens_dev->sensor_num = tsens_num;
+
+       for (sensor_id = 0; sensor_id < tsens_num; sensor_id++) {
+               sensor = &tsens_dev->sensor[sensor_id];
+               sensor->hw_id = sensor_hw_id[sensor_id];
+               tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, sensor_id, sensor,
+                &imx_sc_tsens_ops);
+               if (IS_ERR(tzd)) {
+                       dev_err(&pdev->dev, "failed to register temp sensor: %d\n", sensor_id);
+                       ret = -EINVAL;
+                       goto failed;
+               }
+               sensor->tzd = tzd;
+       }
+
+       return 0;
+failed:
+       return ret;
+}
+
+static int imx_sc_tsens_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static struct platform_driver imx_sc_tsens_driver = {
+               .probe = imx_sc_tsens_probe,
+               .remove = imx_sc_tsens_remove,
+               .driver = {
+                       .name = "i.MX-sc-tsens",
+                       .of_match_table = imx_sc_tsens_table,
+               },
+};
+
+module_platform_driver(imx_sc_tsens_driver);
+
+MODULE_AUTHOR("Jacky Bai<ping.bai@nxp.com");
+MODULE_DESCRIPTION("Thermal driver for NXP i.MX SoCs with system controller");
+MODULE_LICENSE("GPL v2");