Commit 5eed800a authored by Anson Huang's avatar Anson Huang Committed by Daniel Lezcano
Browse files

thermal: imx8mm: Add support for i.MX8MM thermal monitoring unit



i.MX8MM has a thermal monitoring unit(TMU) inside, it ONLY has one
sensor for CPU, add support for reading immediate temperature of
this sensor.

Signed-off-by: default avatarAnson Huang <Anson.Huang@nxp.com>
Signed-off-by: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/1582947862-11073-2-git-send-email-Anson.Huang@nxp.com
parent 444eb18d
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -262,6 +262,16 @@ config IMX_SC_THERMAL
	  sensor. It supports one critical trip point and one
	  passive trip point for each thermal sensor.

config IMX8MM_THERMAL
	tristate "Temperature sensor driver for Freescale i.MX8MM SoC"
	depends on ARCH_MXC
	depends on OF
	help
	  Support for Thermal Monitoring Unit (TMU) found on Freescale i.MX8MM SoC.
	  It supports one critical trip point and one passive trip point. The
	  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
+1 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ 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_IMX8MM_THERMAL)	+= imx8mm_thermal.o
obj-$(CONFIG_MAX77620_THERMAL)	+= max77620_thermal.o
obj-$(CONFIG_QORIQ_THERMAL)	+= qoriq_thermal.o
obj-$(CONFIG_DA9062_THERMAL)	+= da9062-thermal.o
+131 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2020 NXP.
 *
 * Author: Anson Huang <Anson.Huang@nxp.com>
 */

#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>

#include "thermal_core.h"

#define TER			0x0	/* TMU enable */
#define TRITSR			0x20	/* TMU immediate temp */

#define TER_EN			BIT(31)
#define TRITSR_VAL_MASK		0xff

#define TEMP_LOW_LIMIT		10

struct imx8mm_tmu {
	struct thermal_zone_device *tzd;
	void __iomem *base;
	struct clk *clk;
};

static int tmu_get_temp(void *data, int *temp)
{
	struct imx8mm_tmu *tmu = data;
	u32 val;

	val = readl_relaxed(tmu->base + TRITSR) & TRITSR_VAL_MASK;
	if (val < TEMP_LOW_LIMIT)
		return -EAGAIN;

	*temp = val * 1000;

	return 0;
}

static struct thermal_zone_of_device_ops tmu_tz_ops = {
	.get_temp = tmu_get_temp,
};

static int imx8mm_tmu_probe(struct platform_device *pdev)
{
	struct imx8mm_tmu *tmu;
	u32 val;
	int ret;

	tmu = devm_kzalloc(&pdev->dev, sizeof(struct imx8mm_tmu), GFP_KERNEL);
	if (!tmu)
		return -ENOMEM;

	tmu->base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(tmu->base))
		return PTR_ERR(tmu->base);

	tmu->clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(tmu->clk)) {
		ret = PTR_ERR(tmu->clk);
		if (ret != -EPROBE_DEFER)
			dev_err(&pdev->dev,
				"failed to get tmu clock: %d\n", ret);
		return ret;
	}

	ret = clk_prepare_enable(tmu->clk);
	if (ret) {
		dev_err(&pdev->dev, "failed to enable tmu clock: %d\n", ret);
		return ret;
	}

	tmu->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
							tmu, &tmu_tz_ops);
	if (IS_ERR(tmu->tzd)) {
		dev_err(&pdev->dev,
			"failed to register thermal zone sensor: %d\n", ret);
		return PTR_ERR(tmu->tzd);
	}

	platform_set_drvdata(pdev, tmu);

	/* enable the monitor */
	val = readl_relaxed(tmu->base + TER);
	val |= TER_EN;
	writel_relaxed(val, tmu->base + TER);

	return 0;
}

static int imx8mm_tmu_remove(struct platform_device *pdev)
{
	struct imx8mm_tmu *tmu = platform_get_drvdata(pdev);
	u32 val;

	/* disable TMU */
	val = readl_relaxed(tmu->base + TER);
	val &= ~TER_EN;
	writel_relaxed(val, tmu->base + TER);

	clk_disable_unprepare(tmu->clk);
	platform_set_drvdata(pdev, NULL);

	return 0;
}

static const struct of_device_id imx8mm_tmu_table[] = {
	{ .compatible = "fsl,imx8mm-tmu", },
	{ },
};

static struct platform_driver imx8mm_tmu = {
	.driver = {
		.name	= "i.mx8mm_thermal",
		.of_match_table = imx8mm_tmu_table,
	},
	.probe = imx8mm_tmu_probe,
	.remove = imx8mm_tmu_remove,
};
module_platform_driver(imx8mm_tmu);

MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
MODULE_DESCRIPTION("i.MX8MM Thermal Monitor Unit driver");
MODULE_LICENSE("GPL v2");