MLK-14972-02 driver: thermal: Add i.MX8QM/QXP thermal support

Add i.MX8QM/QXP thermal driver support.

Signed-off-by: Bai Ping <ping.bai@nxp.com>
This commit is contained in:
Bai Ping
2017-06-06 13:53:24 +08:00
committed by Nitin Garg
parent 5a600d74d0
commit 10a2548b8b
3 changed files with 179 additions and 0 deletions

View 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

View 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

View File

@ -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");