All of lore.kernel.org
 help / color / mirror / Atom feed
From: Zhang Rui <rui.zhang@intel.com>
To: Jia Hongtao <hongtao.jia@nxp.com>,
	edubezval@gmail.com, robh+dt@kernel.org, galak@codeaurora.org,
	scott.wood@nxp.com, shawnguo@kernel.org
Cc: linux-pm@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH V2 7/7] thermal: qoriq: Add thermal management support
Date: Fri, 19 Aug 2016 20:39:30 +0800	[thread overview]
Message-ID: <1471610370.2691.62.camel@intel.com> (raw)
In-Reply-To: <1467256118-41754-1-git-send-email-hongtao.jia@nxp.com>

On 四, 2016-06-30 at 11:08 +0800, Jia Hongtao wrote:
> This driver add thermal management support by enabling TMU (Thermal
> Monitoring Unit) on QorIQ platform.
> 
> It's based on thermal of framework:
> - Trip points defined in device tree.
> - Cpufreq as cooling device registered in qoriq cpufreq driver.
> 
> Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com>

The patch looks good to me.
I only need to take this patch, right?

thanks,
rui
> ---
> Changes of V2:
> * Add HAS_IOMEM dependency to fix build error on UM
> 
>  drivers/thermal/Kconfig         |  10 ++
>  drivers/thermal/Makefile        |   1 +
>  drivers/thermal/qoriq_thermal.c | 328
> ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 339 insertions(+)
>  create mode 100644 drivers/thermal/qoriq_thermal.c
> 
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 2d702ca..56ef30d 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -195,6 +195,16 @@ config IMX_THERMAL
>  	  cpufreq is used as the cooling device to throttle CPUs
> when the
>  	  passive trip is crossed.
> 
> +config QORIQ_THERMAL
> +	tristate "QorIQ Thermal Monitoring Unit"
> +	depends on THERMAL_OF
> +	depends on HAS_IOMEM
> +	help
> +	  Support for Thermal Monitoring Unit (TMU) found on QorIQ
> platforms.
> +	  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 SPEAR_THERMAL
>  	tristate "SPEAr thermal sensor driver"
>  	depends on PLAT_SPEAR || COMPILE_TEST
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 10b07c1..6662232 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -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_QORIQ_THERMAL)	+= qoriq_thermal.o
>  obj-$(CONFIG_DB8500_CPUFREQ_COOLING)	+=
> db8500_cpufreq_cooling.o
>  obj-$(CONFIG_INTEL_POWERCLAMP)	+= intel_powerclamp.o
>  obj-$(CONFIG_X86_PKG_TEMP_THERMAL)	+= x86_pkg_temp_thermal.o
> diff --git a/drivers/thermal/qoriq_thermal.c
> b/drivers/thermal/qoriq_thermal.c
> new file mode 100644
> index 0000000..644ba52
> --- /dev/null
> +++ b/drivers/thermal/qoriq_thermal.c
> @@ -0,0 +1,328 @@
> +/*
> + * Copyright 2016 Freescale Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but
> WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/thermal.h>
> +
> +#include "thermal_core.h"
> +
> +#define SITES_MAX	16
> +
> +/*
> + * QorIQ TMU Registers
> + */
> +struct qoriq_tmu_site_regs {
> +	u32 tritsr;		/* Immediate Temperature Site
> Register */
> +	u32 tratsr;		/* Average Temperature Site
> Register */
> +	u8 res0[0x8];
> +};
> +
> +struct qoriq_tmu_regs {
> +	u32 tmr;		/* Mode Register */
> +#define TMR_DISABLE	0x0
> +#define TMR_ME		0x80000000
> +#define TMR_ALPF	0x0c000000
> +	u32 tsr;		/* Status Register */
> +	u32 tmtmir;		/* Temperature measurement
> interval Register */
> +#define TMTMIR_DEFAULT	0x0000000f
> +	u8 res0[0x14];
> +	u32 tier;		/* Interrupt Enable Register */
> +#define TIER_DISABLE	0x0
> +	u32 tidr;		/* Interrupt Detect Register */
> +	u32 tiscr;		/* Interrupt Site Capture Register
> */
> +	u32 ticscr;		/* Interrupt Critical Site
> Capture Register */
> +	u8 res1[0x10];
> +	u32 tmhtcrh;		/* High Temperature Capture
> Register */
> +	u32 tmhtcrl;		/* Low Temperature Capture
> Register */
> +	u8 res2[0x8];
> +	u32 tmhtitr;		/* High Temperature Immediate
> Threshold */
> +	u32 tmhtatr;		/* High Temperature Average
> Threshold */
> +	u32 tmhtactr;	/* High Temperature Average Crit
> Threshold */
> +	u8 res3[0x24];
> +	u32 ttcfgr;		/* Temperature Configuration
> Register */
> +	u32 tscfgr;		/* Sensor Configuration Register
> */
> +	u8 res4[0x78];
> +	struct qoriq_tmu_site_regs site[SITES_MAX];
> +	u8 res5[0x9f8];
> +	u32 ipbrr0;		/* IP Block Revision Register 0
> */
> +	u32 ipbrr1;		/* IP Block Revision Register 1
> */
> +	u8 res6[0x310];
> +	u32 ttr0cr;		/* Temperature Range 0 Control
> Register */
> +	u32 ttr1cr;		/* Temperature Range 1 Control
> Register */
> +	u32 ttr2cr;		/* Temperature Range 2 Control
> Register */
> +	u32 ttr3cr;		/* Temperature Range 3 Control
> Register */
> +};
> +
> +/*
> + * Thermal zone data
> + */
> +struct qoriq_tmu_data {
> +	struct thermal_zone_device *tz;
> +	struct qoriq_tmu_regs __iomem *regs;
> +	int sensor_id;
> +	bool little_endian;
> +};
> +
> +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void
> __iomem *addr)
> +{
> +	if (p->little_endian)
> +		iowrite32(val, addr);
> +	else
> +		iowrite32be(val, addr);
> +}
> +
> +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr)
> +{
> +	if (p->little_endian)
> +		return ioread32(addr);
> +	else
> +		return ioread32be(addr);
> +}
> +
> +static int tmu_get_temp(void *p, int *temp)
> +{
> +	u32 val;
> +	struct qoriq_tmu_data *data = p;
> +
> +	val = tmu_read(data, &data->regs->site[data-
> >sensor_id].tritsr);
> +	*temp = (val & 0xff) * 1000;
> +
> +	return 0;
> +}
> +
> +static int qoriq_tmu_get_sensor_id(void)
> +{
> +	int ret, id;
> +	struct of_phandle_args sensor_specs;
> +	struct device_node *np, *sensor_np;
> +
> +	np = of_find_node_by_name(NULL, "thermal-zones");
> +	if (!np)
> +		return -ENODEV;
> +
> +	sensor_np = of_get_next_child(np, NULL);
> +	ret = of_parse_phandle_with_args(sensor_np, "thermal-
> sensors",
> +			"#thermal-sensor-cells",
> +			0, &sensor_specs);
> +	if (ret) {
> +		of_node_put(np);
> +		of_node_put(sensor_np);
> +		return ret;
> +	}
> +
> +	if (sensor_specs.args_count >= 1) {
> +		id = sensor_specs.args[0];
> +		WARN(sensor_specs.args_count > 1,
> +				"%s: too many cells in sensor
> specifier %d\n",
> +				sensor_specs.np->name,
> sensor_specs.args_count);
> +	} else {
> +		id = 0;
> +	}
> +
> +	of_node_put(np);
> +	of_node_put(sensor_np);
> +
> +	return id;
> +}
> +
> +static int qoriq_tmu_calibration(struct platform_device *pdev)
> +{
> +	int i, val, len;
> +	u32 range[4];
> +	const u32 *calibration;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
> +
> +	if (of_property_read_u32_array(np, "fsl,tmu-range", range,
> 4)) {
> +		dev_err(&pdev->dev, "missing calibration range.\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Init temperature range registers */
> +	tmu_write(data, range[0], &data->regs->ttr0cr);
> +	tmu_write(data, range[1], &data->regs->ttr1cr);
> +	tmu_write(data, range[2], &data->regs->ttr2cr);
> +	tmu_write(data, range[3], &data->regs->ttr3cr);
> +
> +	calibration = of_get_property(np, "fsl,tmu-calibration",
> &len);
> +	if (calibration == NULL || len % 8) {
> +		dev_err(&pdev->dev, "invalid calibration data.\n");
> +		return -ENODEV;
> +	}
> +
> +	for (i = 0; i < len; i += 8, calibration += 2) {
> +		val = of_read_number(calibration, 1);
> +		tmu_write(data, val, &data->regs->ttcfgr);
> +		val = of_read_number(calibration + 1, 1);
> +		tmu_write(data, val, &data->regs->tscfgr);
> +	}
> +
> +	return 0;
> +}
> +
> +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data)
> +{
> +	/* Disable interrupt, using polling instead */
> +	tmu_write(data, TIER_DISABLE, &data->regs->tier);
> +
> +	/* Set update_interval */
> +	tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir);
> +
> +	/* Disable monitoring */
> +	tmu_write(data, TMR_DISABLE, &data->regs->tmr);
> +}
> +
> +static struct thermal_zone_of_device_ops tmu_tz_ops = {
> +	.get_temp = tmu_get_temp,
> +};
> +
> +static int qoriq_tmu_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	const struct thermal_trip *trip;
> +	struct qoriq_tmu_data *data;
> +	struct device_node *np = pdev->dev.of_node;
> +	u32 site = 0;
> +
> +	if (!np) {
> +		dev_err(&pdev->dev, "Device OF-Node is NULL");
> +		return -ENODEV;
> +	}
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(struct
> qoriq_tmu_data),
> +			    GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	data->little_endian = of_property_read_bool(np, "little-
> endian");
> +
> +	data->sensor_id = qoriq_tmu_get_sensor_id();
> +	if (data->sensor_id < 0) {
> +		dev_err(&pdev->dev, "Failed to get sensor id\n");
> +		ret = -ENODEV;
> +		goto err_iomap;
> +	}
> +
> +	data->regs = of_iomap(np, 0);
> +	if (!data->regs) {
> +		dev_err(&pdev->dev, "Failed to get memory
> region\n");
> +		ret = -ENODEV;
> +		goto err_iomap;
> +	}
> +
> +	qoriq_tmu_init_device(data);	/* TMU initialization */
> +
> +	ret = qoriq_tmu_calibration(pdev);	/* TMU calibration
> */
> +	if (ret < 0)
> +		goto err_tmu;
> +
> +	data->tz = thermal_zone_of_sensor_register(&pdev->dev, data-
> >sensor_id,
> +				data, &tmu_tz_ops);
> +	if (IS_ERR(data->tz)) {
> +		ret = PTR_ERR(data->tz);
> +		dev_err(&pdev->dev,
> +			"Failed to register thermal zone device
> %d\n", ret);
> +		goto err_tmu;
> +	}
> +
> +	trip = of_thermal_get_trip_points(data->tz);
> +
> +	/* Enable monitoring */
> +	site |= 0x1 << (15 - data->sensor_id);
> +	tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr);
> +
> +	return 0;
> +
> +err_tmu:
> +	iounmap(data->regs);
> +
> +err_iomap:
> +	platform_set_drvdata(pdev, NULL);
> +
> +	return ret;
> +}
> +
> +static int qoriq_tmu_remove(struct platform_device *pdev)
> +{
> +	struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
> +
> +	thermal_zone_of_sensor_unregister(&pdev->dev, data->tz);
> +
> +	/* Disable monitoring */
> +	tmu_write(data, TMR_DISABLE, &data->regs->tmr);
> +
> +	iounmap(data->regs);
> +	platform_set_drvdata(pdev, NULL);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int qoriq_tmu_suspend(struct device *dev)
> +{
> +	u32 tmr;
> +	struct qoriq_tmu_data *data = dev_get_drvdata(dev);
> +
> +	/* Disable monitoring */
> +	tmr = tmu_read(data, &data->regs->tmr);
> +	tmr &= ~TMR_ME;
> +	tmu_write(data, tmr, &data->regs->tmr);
> +
> +	return 0;
> +}
> +
> +static int qoriq_tmu_resume(struct device *dev)
> +{
> +	u32 tmr;
> +	struct qoriq_tmu_data *data = dev_get_drvdata(dev);
> +
> +	/* Enable monitoring */
> +	tmr = tmu_read(data, &data->regs->tmr);
> +	tmr |= TMR_ME;
> +	tmu_write(data, tmr, &data->regs->tmr);
> +
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
> +			 qoriq_tmu_suspend, qoriq_tmu_resume);
> +
> +static const struct of_device_id qoriq_tmu_match[] = {
> +	{ .compatible = "fsl,qoriq-tmu", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
> +
> +static struct platform_driver qoriq_tmu = {
> +	.driver	= {
> +		.name		= "qoriq_thermal",
> +		.pm		= &qoriq_tmu_pm_ops,
> +		.of_match_table	= qoriq_tmu_match,
> +	},
> +	.probe	= qoriq_tmu_probe,
> +	.remove	= qoriq_tmu_remove,
> +};
> +module_platform_driver(qoriq_tmu);
> +
> +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>");
> +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.1.0.27.g96db324
> 

WARNING: multiple messages have this Message-ID (diff)
From: rui.zhang@intel.com (Zhang Rui)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH V2 7/7] thermal: qoriq: Add thermal management support
Date: Fri, 19 Aug 2016 20:39:30 +0800	[thread overview]
Message-ID: <1471610370.2691.62.camel@intel.com> (raw)
In-Reply-To: <1467256118-41754-1-git-send-email-hongtao.jia@nxp.com>

On ?, 2016-06-30 at 11:08 +0800, Jia Hongtao wrote:
> This driver add thermal management support by enabling TMU (Thermal
> Monitoring Unit) on QorIQ platform.
> 
> It's based on thermal of framework:
> - Trip points defined in device tree.
> - Cpufreq as cooling device registered in qoriq cpufreq driver.
> 
> Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com>

The patch looks good to me.
I only need to take this patch, right?

thanks,
rui
> ---
> Changes of V2:
> * Add HAS_IOMEM dependency to fix build error on UM
> 
> ?drivers/thermal/Kconfig?????????|??10 ++
> ?drivers/thermal/Makefile????????|???1 +
> ?drivers/thermal/qoriq_thermal.c | 328
> ++++++++++++++++++++++++++++++++++++++++
> ?3 files changed, 339 insertions(+)
> ?create mode 100644 drivers/thermal/qoriq_thermal.c
> 
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 2d702ca..56ef30d 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -195,6 +195,16 @@ config IMX_THERMAL
> ?	??cpufreq is used as the cooling device to throttle CPUs
> when the
> ?	??passive trip is crossed.
> 
> +config QORIQ_THERMAL
> +	tristate "QorIQ Thermal Monitoring Unit"
> +	depends on THERMAL_OF
> +	depends on HAS_IOMEM
> +	help
> +	??Support for Thermal Monitoring Unit (TMU) found on QorIQ
> platforms.
> +	??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 SPEAR_THERMAL
> ?	tristate "SPEAr thermal sensor driver"
> ?	depends on PLAT_SPEAR || COMPILE_TEST
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 10b07c1..6662232 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -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_QORIQ_THERMAL)	+= qoriq_thermal.o
> ?obj-$(CONFIG_DB8500_CPUFREQ_COOLING)	+=
> db8500_cpufreq_cooling.o
> ?obj-$(CONFIG_INTEL_POWERCLAMP)	+= intel_powerclamp.o
> ?obj-$(CONFIG_X86_PKG_TEMP_THERMAL)	+= x86_pkg_temp_thermal.o
> diff --git a/drivers/thermal/qoriq_thermal.c
> b/drivers/thermal/qoriq_thermal.c
> new file mode 100644
> index 0000000..644ba52
> --- /dev/null
> +++ b/drivers/thermal/qoriq_thermal.c
> @@ -0,0 +1,328 @@
> +/*
> + * Copyright 2016 Freescale Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but
> WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.??See the GNU General Public
> License for
> + * more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/thermal.h>
> +
> +#include "thermal_core.h"
> +
> +#define SITES_MAX	16
> +
> +/*
> + * QorIQ TMU Registers
> + */
> +struct qoriq_tmu_site_regs {
> +	u32 tritsr;		/* Immediate Temperature Site
> Register */
> +	u32 tratsr;		/* Average Temperature Site
> Register */
> +	u8 res0[0x8];
> +};
> +
> +struct qoriq_tmu_regs {
> +	u32 tmr;		/* Mode Register */
> +#define TMR_DISABLE	0x0
> +#define TMR_ME		0x80000000
> +#define TMR_ALPF	0x0c000000
> +	u32 tsr;		/* Status Register */
> +	u32 tmtmir;		/* Temperature measurement
> interval Register */
> +#define TMTMIR_DEFAULT	0x0000000f
> +	u8 res0[0x14];
> +	u32 tier;		/* Interrupt Enable Register */
> +#define TIER_DISABLE	0x0
> +	u32 tidr;		/* Interrupt Detect Register */
> +	u32 tiscr;		/* Interrupt Site Capture Register
> */
> +	u32 ticscr;		/* Interrupt Critical Site
> Capture Register */
> +	u8 res1[0x10];
> +	u32 tmhtcrh;		/* High Temperature Capture
> Register */
> +	u32 tmhtcrl;		/* Low Temperature Capture
> Register */
> +	u8 res2[0x8];
> +	u32 tmhtitr;		/* High Temperature Immediate
> Threshold */
> +	u32 tmhtatr;		/* High Temperature Average
> Threshold */
> +	u32 tmhtactr;	/* High Temperature Average Crit
> Threshold */
> +	u8 res3[0x24];
> +	u32 ttcfgr;		/* Temperature Configuration
> Register */
> +	u32 tscfgr;		/* Sensor Configuration Register
> */
> +	u8 res4[0x78];
> +	struct qoriq_tmu_site_regs site[SITES_MAX];
> +	u8 res5[0x9f8];
> +	u32 ipbrr0;		/* IP Block Revision Register 0
> */
> +	u32 ipbrr1;		/* IP Block Revision Register 1
> */
> +	u8 res6[0x310];
> +	u32 ttr0cr;		/* Temperature Range 0 Control
> Register */
> +	u32 ttr1cr;		/* Temperature Range 1 Control
> Register */
> +	u32 ttr2cr;		/* Temperature Range 2 Control
> Register */
> +	u32 ttr3cr;		/* Temperature Range 3 Control
> Register */
> +};
> +
> +/*
> + * Thermal zone data
> + */
> +struct qoriq_tmu_data {
> +	struct thermal_zone_device *tz;
> +	struct qoriq_tmu_regs __iomem *regs;
> +	int sensor_id;
> +	bool little_endian;
> +};
> +
> +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void
> __iomem *addr)
> +{
> +	if (p->little_endian)
> +		iowrite32(val, addr);
> +	else
> +		iowrite32be(val, addr);
> +}
> +
> +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr)
> +{
> +	if (p->little_endian)
> +		return ioread32(addr);
> +	else
> +		return ioread32be(addr);
> +}
> +
> +static int tmu_get_temp(void *p, int *temp)
> +{
> +	u32 val;
> +	struct qoriq_tmu_data *data = p;
> +
> +	val = tmu_read(data, &data->regs->site[data-
> >sensor_id].tritsr);
> +	*temp = (val & 0xff) * 1000;
> +
> +	return 0;
> +}
> +
> +static int qoriq_tmu_get_sensor_id(void)
> +{
> +	int ret, id;
> +	struct of_phandle_args sensor_specs;
> +	struct device_node *np, *sensor_np;
> +
> +	np = of_find_node_by_name(NULL, "thermal-zones");
> +	if (!np)
> +		return -ENODEV;
> +
> +	sensor_np = of_get_next_child(np, NULL);
> +	ret = of_parse_phandle_with_args(sensor_np, "thermal-
> sensors",
> +			"#thermal-sensor-cells",
> +			0, &sensor_specs);
> +	if (ret) {
> +		of_node_put(np);
> +		of_node_put(sensor_np);
> +		return ret;
> +	}
> +
> +	if (sensor_specs.args_count >= 1) {
> +		id = sensor_specs.args[0];
> +		WARN(sensor_specs.args_count > 1,
> +				"%s: too many cells in sensor
> specifier %d\n",
> +				sensor_specs.np->name,
> sensor_specs.args_count);
> +	} else {
> +		id = 0;
> +	}
> +
> +	of_node_put(np);
> +	of_node_put(sensor_np);
> +
> +	return id;
> +}
> +
> +static int qoriq_tmu_calibration(struct platform_device *pdev)
> +{
> +	int i, val, len;
> +	u32 range[4];
> +	const u32 *calibration;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
> +
> +	if (of_property_read_u32_array(np, "fsl,tmu-range", range,
> 4)) {
> +		dev_err(&pdev->dev, "missing calibration range.\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Init temperature range registers */
> +	tmu_write(data, range[0], &data->regs->ttr0cr);
> +	tmu_write(data, range[1], &data->regs->ttr1cr);
> +	tmu_write(data, range[2], &data->regs->ttr2cr);
> +	tmu_write(data, range[3], &data->regs->ttr3cr);
> +
> +	calibration = of_get_property(np, "fsl,tmu-calibration",
> &len);
> +	if (calibration == NULL || len % 8) {
> +		dev_err(&pdev->dev, "invalid calibration data.\n");
> +		return -ENODEV;
> +	}
> +
> +	for (i = 0; i < len; i += 8, calibration += 2) {
> +		val = of_read_number(calibration, 1);
> +		tmu_write(data, val, &data->regs->ttcfgr);
> +		val = of_read_number(calibration + 1, 1);
> +		tmu_write(data, val, &data->regs->tscfgr);
> +	}
> +
> +	return 0;
> +}
> +
> +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data)
> +{
> +	/* Disable interrupt, using polling instead */
> +	tmu_write(data, TIER_DISABLE, &data->regs->tier);
> +
> +	/* Set update_interval */
> +	tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir);
> +
> +	/* Disable monitoring */
> +	tmu_write(data, TMR_DISABLE, &data->regs->tmr);
> +}
> +
> +static struct thermal_zone_of_device_ops tmu_tz_ops = {
> +	.get_temp = tmu_get_temp,
> +};
> +
> +static int qoriq_tmu_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	const struct thermal_trip *trip;
> +	struct qoriq_tmu_data *data;
> +	struct device_node *np = pdev->dev.of_node;
> +	u32 site = 0;
> +
> +	if (!np) {
> +		dev_err(&pdev->dev, "Device OF-Node is NULL");
> +		return -ENODEV;
> +	}
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(struct
> qoriq_tmu_data),
> +			????GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	data->little_endian = of_property_read_bool(np, "little-
> endian");
> +
> +	data->sensor_id = qoriq_tmu_get_sensor_id();
> +	if (data->sensor_id < 0) {
> +		dev_err(&pdev->dev, "Failed to get sensor id\n");
> +		ret = -ENODEV;
> +		goto err_iomap;
> +	}
> +
> +	data->regs = of_iomap(np, 0);
> +	if (!data->regs) {
> +		dev_err(&pdev->dev, "Failed to get memory
> region\n");
> +		ret = -ENODEV;
> +		goto err_iomap;
> +	}
> +
> +	qoriq_tmu_init_device(data);	/* TMU initialization */
> +
> +	ret = qoriq_tmu_calibration(pdev);	/* TMU calibration
> */
> +	if (ret < 0)
> +		goto err_tmu;
> +
> +	data->tz = thermal_zone_of_sensor_register(&pdev->dev, data-
> >sensor_id,
> +				data, &tmu_tz_ops);
> +	if (IS_ERR(data->tz)) {
> +		ret = PTR_ERR(data->tz);
> +		dev_err(&pdev->dev,
> +			"Failed to register thermal zone device
> %d\n", ret);
> +		goto err_tmu;
> +	}
> +
> +	trip = of_thermal_get_trip_points(data->tz);
> +
> +	/* Enable monitoring */
> +	site |= 0x1 << (15 - data->sensor_id);
> +	tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr);
> +
> +	return 0;
> +
> +err_tmu:
> +	iounmap(data->regs);
> +
> +err_iomap:
> +	platform_set_drvdata(pdev, NULL);
> +
> +	return ret;
> +}
> +
> +static int qoriq_tmu_remove(struct platform_device *pdev)
> +{
> +	struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
> +
> +	thermal_zone_of_sensor_unregister(&pdev->dev, data->tz);
> +
> +	/* Disable monitoring */
> +	tmu_write(data, TMR_DISABLE, &data->regs->tmr);
> +
> +	iounmap(data->regs);
> +	platform_set_drvdata(pdev, NULL);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int qoriq_tmu_suspend(struct device *dev)
> +{
> +	u32 tmr;
> +	struct qoriq_tmu_data *data = dev_get_drvdata(dev);
> +
> +	/* Disable monitoring */
> +	tmr = tmu_read(data, &data->regs->tmr);
> +	tmr &= ~TMR_ME;
> +	tmu_write(data, tmr, &data->regs->tmr);
> +
> +	return 0;
> +}
> +
> +static int qoriq_tmu_resume(struct device *dev)
> +{
> +	u32 tmr;
> +	struct qoriq_tmu_data *data = dev_get_drvdata(dev);
> +
> +	/* Enable monitoring */
> +	tmr = tmu_read(data, &data->regs->tmr);
> +	tmr |= TMR_ME;
> +	tmu_write(data, tmr, &data->regs->tmr);
> +
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
> +			?qoriq_tmu_suspend, qoriq_tmu_resume);
> +
> +static const struct of_device_id qoriq_tmu_match[] = {
> +	{ .compatible = "fsl,qoriq-tmu", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
> +
> +static struct platform_driver qoriq_tmu = {
> +	.driver	= {
> +		.name		= "qoriq_thermal",
> +		.pm		= &qoriq_tmu_pm_ops,
> +		.of_match_table	= qoriq_tmu_match,
> +	},
> +	.probe	= qoriq_tmu_probe,
> +	.remove	= qoriq_tmu_remove,
> +};
> +module_platform_driver(qoriq_tmu);
> +
> +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>");
> +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.1.0.27.g96db324
> 

  parent reply	other threads:[~2016-08-19 12:39 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-30  3:08 [PATCH V2 7/7] thermal: qoriq: Add thermal management support Jia Hongtao
2016-06-30  3:08 ` Jia Hongtao
2016-06-30  3:08 ` Jia Hongtao
2016-07-19  6:54 ` Hongtao Jia
2016-07-19  6:54   ` Hongtao Jia
2016-07-19  6:54   ` Hongtao Jia
2016-07-19  6:54   ` Hongtao Jia
2016-08-05  6:26   ` Hongtao Jia
2016-08-05  6:26     ` Hongtao Jia
2016-08-05  6:26     ` Hongtao Jia
2016-08-05  6:26     ` Hongtao Jia
2016-08-19 12:39 ` Zhang Rui [this message]
2016-08-19 12:39   ` Zhang Rui
2016-08-19 12:39   ` Zhang Rui
2016-09-08  7:11   ` Troy Jia
2016-09-08  7:11     ` Troy Jia
2016-09-08  7:11     ` Troy Jia
2016-09-08  7:11     ` Troy Jia

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1471610370.2691.62.camel@intel.com \
    --to=rui.zhang@intel.com \
    --cc=devicetree@vger.kernel.org \
    --cc=edubezval@gmail.com \
    --cc=galak@codeaurora.org \
    --cc=hongtao.jia@nxp.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=robh+dt@kernel.org \
    --cc=scott.wood@nxp.com \
    --cc=shawnguo@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.