All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v4 1/4] thermal: rockchip: add driver for thermal
  2014-09-03  2:10   ` Caesar Wang
@ 2014-08-30 20:09     ` Eduardo Valentin
  -1 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-08-30 20:09 UTC (permalink / raw)
  To: Caesar Wang
  Cc: heiko, rui.zhang, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov, zhaoyifeng

Hello Ceasar,

On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
> Thermal is TS-ADC Controller module supports
> user-defined mode and automatic mode.
> 
> User-defined mode refers,TSADC all the control signals entirely by
> software writing to register for direct control.
> 
> Automaic mode refers to the module automatically poll TSADC output,
> and the results were checked.If you find that the temperature High
> in a period of time,an interrupt is generated to the processor
> down-measures taken;if the temperature over a period of time High,
> the resulting TSHUT gave CRU module,let it reset the entire chip,
> or via GPIO give PMIC.
> 
> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> ---
>  drivers/thermal/Kconfig            |   9 +
>  drivers/thermal/Makefile           |   1 +
>  drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 679 insertions(+)
>  create mode 100644 drivers/thermal/rockchip_thermal.c
> 
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index f9a1386..a00aa1e 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
>  	  Enable this to plug the SPEAr thermal sensor driver into the Linux
>  	  thermal framework.
>  
> +config ROCKCHIP_THERMAL
> +	tristate "Rockchip thermal driver"
> +	depends on ARCH_ROCKCHIP
> +	help
> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
> +	  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 RCAR_THERMAL
>  	tristate "Renesas R-Car thermal driver"
>  	depends on ARCH_SHMOBILE || COMPILE_TEST
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index de0636a..b48b817 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
>  
>  # platform thermal drivers
>  obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
>  obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
>  obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
>  obj-y				+= samsung/
> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
> new file mode 100644
> index 0000000..011f387
> --- /dev/null
> +++ b/drivers/thermal/rockchip_thermal.c
> @@ -0,0 +1,669 @@
> +/*
> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
> + *
> + * 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/clk.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/cpu_cooling.h>
> +#include "thermal_core.h"

Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
sufficient?

> +
> +enum rockchip_thermal_trip {
> +	ROCKCHIP_TRIP_PASSIVE,
> +	ROCKCHIP_TRIP_CRITICAL,
> +	ROCKCHIP_TRIP_NUM,
> +};
> +

Why do you need your own trip types?

> +struct rockchip_thermal_data {
> +	const struct rockchip_tsadc_platform_data *pdata;
> +	struct thermal_zone_device *tz;
> +	struct thermal_cooling_device *cdev;
> +	enum thermal_device_mode mode;
> +	void __iomem *regs;
> +
> +	signed long temp_passive;
> +	signed long temp_critical;
> +	signed long temp_force_shut;
> +	signed long alarm_temp;
> +	signed long last_temp;
> +	bool irq_enabled;
> +	int irq;
> +	struct clk *clk;
> +	struct clk *pclk;
> +};
> +
> +struct rockchip_tsadc_platform_data {
> +	u8 irq_en;
> +	signed long temp_passive;
> +	signed long temp_critical;
> +	signed long temp_force_shut;
> +	int passive_delay;
> +	int polling_delay;
> +
> +	int (*irq_handle)(void __iomem *reg);
> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
> +	int (*control)(void __iomem *reg, bool on);
> +	u32 (*code_to_temp)(int temp);
> +	u32 (*temp_to_code)(int temp);
> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
> +};
> +
> +/*TSADC V2 Sensor info define:*/
> +#define TSADCV2_AUTO_CON			0x04
> +#define TSADCV2_INT_EN				0x08
> +#define TSADCV2_INT_PD				0x0c
> +#define TSADCV2_DATA1				0x24
> +#define TSADCV2_COMP1_INT			0x34
> +#define TSADCV2_COMP1_SHUT			0x44
> +#define TSADCV2_AUTO_PERIOD			0x68
> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
> +
> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
> +#define TSADCV2_AUTO_EN				(1 << 0)
> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
> +

The above bits can be defined with BIT() macro, right? Something like:
+#define TSADCV2_INT_SRC1_STATUS			BIT(1)


> +#define TSADCV2_DATA_MASK			0xfff
> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
> +
> +struct tsadc_table {
> +	int code;
> +	int temp;
> +};
> +
> +static const struct tsadc_table v2_code_table[] = {
> +	{TSADCV2_DATA_MASK, -40},
> +	{3800, -40},
> +	{3792, -35},
> +	{3783, -30},
> +	{3774, -25},
> +	{3765, -20},
> +	{3756, -15},
> +	{3747, -10},
> +	{3737, -5},
> +	{3728, 0},
> +	{3718, 5},
> +	{3708, 10},
> +	{3698, 15},
> +	{3688, 20},
> +	{3678, 25},
> +	{3667, 30},
> +	{3656, 35},
> +	{3645, 40},
> +	{3634, 45},
> +	{3623, 50},
> +	{3611, 55},
> +	{3600, 60},
> +	{3588, 65},
> +	{3575, 70},
> +	{3563, 75},
> +	{3550, 80},
> +	{3537, 85},
> +	{3524, 90},
> +	{3510, 95},
> +	{3496, 100},
> +	{3482, 105},
> +	{3467, 110},
> +	{3452, 115},
> +	{3437, 120},
> +	{3421, 125},
> +	{0, 125},
> +};
> +
> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);

Why do you need to clear bit 8? Why hardcoded?

> +
> +	return 0;
> +}
> +
> +static u32 rk_tsadcv2_temp_to_code(int temp)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
> +		if (temp <= v2_code_table[i].temp && temp >
> +		    v2_code_table[i - 1].temp)
> +			return v2_code_table[i].code;
> +	}
> +
> +	return 0;
> +}
> +
> +static u32 rk_tsadcv2_code_to_temp(int code)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
> +		if (code <= v2_code_table[i].code && code >
> +		    v2_code_table[i + 1].code){
> +			return v2_code_table[i].temp;
> +		}
> +	}
> +
> +	return 0;
> +}

I know the table is not something too big, but considering it is ordered
by either ADC value code or by temp, at least one of the above searching function
may be more efficient, right?

> +
> +static int rk_tsadcv2_initialize(void __iomem *regs,
> +				 signed long temp_force_shut)
> +{
> +	int shutdown_value;
> +
> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
> +	/* Enable measurements at ~ 10 Hz */

Does it leave the sampling clock at 10Hz? Is this clock exposed via
clock framework?

> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
> +		       TSADCV2_AUTO_PERIOD_HT);
> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
> +		       TSADCV2_INT_EN);
> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
> +		       TSADCV2_AUTO_CON);
> +
> +	return 0;
> +}
> +
> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
> +{
> +	u32 val;
> +
> +	if (on) {
> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
> +	} else {
> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
> +			       regs + TSADCV2_AUTO_CON);
> +	}
> +
> +	return 0;
> +}
> +
> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
> +{
> +	int alarm_value;
> +
> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
> +}
> +
> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
> +	.irq_en = 1,
> +	.temp_passive = 85000,
> +	.temp_critical = 100000,
> +	.temp_force_shut = 120000,
> +	.passive_delay = 2000,
> +	.polling_delay = 1000,
> +	.irq_handle = rk_tsadcv2_irq_handle,
> +	.initialize = rk_tsadcv2_initialize,
> +	.control = rk_tsadcv2_control,
> +	.code_to_temp = rk_tsadcv2_code_to_temp,
> +	.temp_to_code = rk_tsadcv2_temp_to_code,
> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
> +};

shall the above struct be also static?

> +
> +static const struct of_device_id of_rockchip_thermal_match[] = {
> +	{
> +		.compatible = "rockchip,rk3288-tsadc",
> +		.data = (void *)&rk3288_tsadc_data,
> +	},
> +	{ /* end */ },
> +};
> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
> +
> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
> +				    signed long alarm_temp)
> +{
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +
> +	data->alarm_temp = alarm_temp;
> +	if (p_tsadc_data->set_alarm_temp)
> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
> +}
> +
> +static int rockchip_get_temp(struct thermal_zone_device *tz,
> +			     unsigned long *temp)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +	u32 val;
> +
> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
> +	*temp = p_tsadc_data->code_to_temp(val);
> +
> +	/* Update alarm value to next higher trip point */
> +	if (data->alarm_temp == data->temp_passive && *temp >=
> +	    data->temp_passive)
> +		rockchip_set_alarm_temp(data, data->temp_critical);
> +
> +	if (data->alarm_temp == data->temp_critical && *temp <
> +	    data->temp_passive) {
> +		rockchip_set_alarm_temp(data, data->temp_passive);
> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
> +			data->alarm_temp / 1000);
> +	}
> +
> +	if (*temp != data->last_temp) {
> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
> +		data->last_temp = *temp;
> +	}
> +
> +	/* Reenable alarm IRQ if temperature below alarm temperature */
> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
> +		data->irq_enabled = true;
> +		enable_irq(data->irq);
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
> +{
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +
> +	if (p_tsadc_data->initialize)
> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
> +	rockchip_set_alarm_temp(data, data->temp_passive);
> +
> +	return 0;
> +}
> +
> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
> +				     bool on)
> +{
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +
> +	if (p_tsadc_data->control)
> +		p_tsadc_data->control(data->regs, on);
> +
> +	if (on) {
> +		data->irq_enabled = true;
> +		data->mode = THERMAL_DEVICE_ENABLED;
> +	} else {
> +		data->irq_enabled = false;
> +		data->mode = THERMAL_DEVICE_DISABLED;
> +	}
> +}
> +
> +static int rockchip_get_mode(struct thermal_zone_device *tz,
> +			     enum thermal_device_mode *mode)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +
> +	*mode = data->mode;
> +
> +	return 0;
> +}
> +
> +static int rockchip_set_mode(struct thermal_zone_device *tz,
> +			     enum thermal_device_mode mode)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +
> +	if (mode == THERMAL_DEVICE_ENABLED) {
> +		tz->polling_delay = p_tsadc_data->polling_delay;
> +		tz->passive_delay = p_tsadc_data->passive_delay;
> +		if (!data->irq_enabled) {
> +			data->irq_enabled = true;
> +			enable_irq(data->irq);
> +		}
> +	} else {
> +		tz->polling_delay = 0;
> +		tz->passive_delay = 0;
> +		if (data->irq_enabled) {
> +			disable_irq(data->irq);
> +			data->irq_enabled = false;
> +		}
> +	}
> +
> +	data->mode = mode;
> +	thermal_zone_device_update(tz);
> +
> +	return 0;
> +}
> +
> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
> +				  enum thermal_trip_type *type)
> +{
> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
> +		 THERMAL_TRIP_CRITICAL;
> +
> +	return 0;
> +}
> +
> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
> +				  unsigned long *temp)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +
> +	*temp = data->temp_critical;
> +
> +	return 0;
> +}
> +
> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
> +				  unsigned long *temp)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +
> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
> +		 data->temp_critical;
> +
> +	return 0;
> +}
> +
> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
> +				  unsigned long temp)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +
> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
> +		return -EPERM;
> +
> +	data->temp_passive = temp;
> +	rockchip_set_alarm_temp(data, temp);
> +
> +	return 0;
> +}
> +
> +static int rockchip_bind(struct thermal_zone_device *tz,
> +			 struct thermal_cooling_device *cdev)
> +{
> +	int ret;
> +
> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
> +					       THERMAL_NO_LIMIT,
> +					       THERMAL_NO_LIMIT);
> +	if (ret) {
> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> +			tz->type, cdev->type, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_unbind(struct thermal_zone_device *tz,
> +			   struct thermal_cooling_device *cdev)
> +{
> +	int ret;
> +
> +	ret = thermal_zone_unbind_cooling_device(tz,
> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
> +	if (ret) {
> +		dev_err(&tz->device,
> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
> +			cdev->type, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}

The method of binding and unbinding used above requires you to check if
you are binding to the right cdev. If in your system you register more
than one cdev, say someone loads the power supply core, which in turns
register a cooling device for charging, your thermal zone will bind it
to TRIP_PASSIVE. It will happen to any cooling device that eventually
gets registered to the thermal framework. Is that the desired outcome?

If not, you may want to compare the paramenter cdev to your data->cdev.

> +
> +static struct thermal_zone_device_ops rockchip_tz_ops = {
> +	.bind = rockchip_bind,
> +	.unbind = rockchip_unbind,
> +	.get_temp = rockchip_get_temp,
> +	.get_mode = rockchip_get_mode,
> +	.set_mode = rockchip_set_mode,
> +	.get_trip_type = rockchip_get_trip_type,
> +	.get_trip_temp = rockchip_get_trip_temp,
> +	.get_crit_temp = rockchip_get_crit_temp,
> +	.set_trip_temp = rockchip_set_trip_temp,
> +};
> +
> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
> +{
> +	struct rockchip_thermal_data *data = data;
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +
> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
> +		data->alarm_temp / 1000);
> +
> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
> +		p_tsadc_data->irq_handle(data->regs);
> +
> +	thermal_zone_device_update(data->tz);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int rockchip_thermal_probe(struct platform_device *pdev)
> +{
> +	struct rockchip_thermal_data *data;
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
> +	struct cpumask clip_cpus;
> +	struct resource *res;
> +	const struct of_device_id *match;
> +	int ret, temp;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
> +			    GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->regs)) {
> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
> +			data->regs);
> +		return PTR_ERR(data->regs);
> +	}
> +
> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
> +	if (!match)
> +		return -ENXIO;
> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
> +	if (!data->pdata)
> +		return -EINVAL;
> +	p_tsadc_data = data->pdata;
> +
> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
> +	if (IS_ERR(data->clk)) {
> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
> +		return PTR_ERR(data->clk);
> +	}
> +
> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
> +	if (IS_ERR(data->pclk)) {
> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
> +		return PTR_ERR(data->pclk);
> +	}
> +
> +	/*
> +	* Use a default of 10KHz for the converter clock.
> +	* This may become user-configurable in the future.
> +	*/
> +	ret = clk_set_rate(data->clk, 10000);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(data->clk);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
> +		goto err_clk;
> +	}
> +
> +	ret = clk_prepare_enable(data->pclk);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to enable pclk\n");
> +		goto err_pclk;
> +	}
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
> +		dev_warn(&pdev->dev,
> +			 "Missing default passive temp property in the DT.\n");
> +		data->temp_passive = p_tsadc_data->temp_passive;
> +	} else {
> +		data->temp_passive = temp;
> +	}
> +
> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
> +		dev_warn(&pdev->dev,
> +			 "Missing default critical temp property in the DT.\n");
> +		data->temp_critical = p_tsadc_data->temp_critical;
> +	} else {
> +		data->temp_critical = temp;
> +	}
> +
> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
> +		dev_warn(&pdev->dev,
> +			 "Missing default force shut down temp property in the DT.\n");
> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
> +	} else {
> +		data->temp_force_shut = temp;
> +	}
> +
> +	cpumask_set_cpu(0, &clip_cpus);
> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
> +	if (IS_ERR(data->cdev)) {
> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
> +		goto disable_clk;
> +	}
> +
> +	data->tz = thermal_zone_device_register("rockchip_thermal",
> +						ROCKCHIP_TRIP_NUM,
> +						0, data,
> +						&rockchip_tz_ops, NULL,
> +						p_tsadc_data->passive_delay,
> +						p_tsadc_data->polling_delay);
> +
> +	if (IS_ERR(data->tz)) {
> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
> +		goto fail_cpufreq_register;
> +	}
> +
> +	if (p_tsadc_data->irq_en) {
> +		data->irq = platform_get_irq(pdev, 0);
> +		if (data->irq < 0) {
> +			dev_err(&pdev->dev, "no irq resource?\n");
> +			goto fail_irq;
> +		}
> +
> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
> +				rockchip_thermal_alarm_irq_thread,
> +				IRQF_ONESHOT, "rockchip_thermal", data);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev,
> +				"failed to request tsadc irq: %d\n", ret);
> +			goto fail_thermal_unregister;
> +		}
> +	}
> +
> +	rockchip_thermal_initialize(data);
> +	rockchip_thermal_control(data, true);
> +
> +	return 0;
> +
> +fail_thermal_unregister:
> +	thermal_zone_device_unregister(data->tz);
> +fail_irq:
> +fail_cpufreq_register:
> +	cpufreq_cooling_unregister(data->cdev);
> +disable_clk:
> +err_pclk:
> +	clk_disable_unprepare(data->pclk);
> +err_clk:
> +	clk_disable_unprepare(data->clk);
> +
> +	return ret;
> +}
> +
> +static int rockchip_thermal_remove(struct platform_device *pdev)
> +{
> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> +
> +	rockchip_thermal_control(data, false);
> +
> +	thermal_zone_device_unregister(data->tz);
> +	cpufreq_cooling_unregister(data->cdev);
> +	cpufreq_cooling_unregister(data->cdev);
> +

The above call is duplicated.

> +	clk_disable_unprepare(data->clk);
> +	clk_disable_unprepare(data->pclk);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int rockchip_thermal_suspend(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> +
> +	rockchip_thermal_control(data, false);
> +
> +	return 0;
> +}
> +
> +static int rockchip_thermal_resume(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> +
> +	rockchip_thermal_initialize(data);
> +	rockchip_thermal_control(data, true);
> +
> +	return 0;
> +}

Would you need to manage your clocks too in the suspend resume path
(data->clk and data->pclk)?

> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
> +
> +static struct platform_driver rockchip_thermal_driver = {
> +	.driver = {
> +		   .name = "rockchip-thermal",
> +		   .owner = THIS_MODULE,
> +		   .pm = &rockchip_thermal_pm_ops,
> +		   .of_match_table = of_rockchip_thermal_match,
> +		   },
> +	.probe = rockchip_thermal_probe,
> +	.remove = rockchip_thermal_remove,
> +};
> +
> +module_platform_driver(rockchip_thermal_driver);
> +
> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
> +MODULE_AUTHOR("Rockchip, Inc.");
> +MODULE_LICENSE("GPL");

Your file header states GPL version two. Thus I suppose you meant:
+MODULE_LICENSE("GPL v2");

right?

Check include/linux/module.h for further clarifications.

> +MODULE_ALIAS("platform:rockchip-thermal");
> -- 
> 1.9.1
> 
> 

BR,

Eduardo Valentin

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 1/4] thermal: rockchip: add driver for thermal
@ 2014-08-30 20:09     ` Eduardo Valentin
  0 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-08-30 20:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Ceasar,

On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
> Thermal is TS-ADC Controller module supports
> user-defined mode and automatic mode.
> 
> User-defined mode refers,TSADC all the control signals entirely by
> software writing to register for direct control.
> 
> Automaic mode refers to the module automatically poll TSADC output,
> and the results were checked.If you find that the temperature High
> in a period of time,an interrupt is generated to the processor
> down-measures taken;if the temperature over a period of time High,
> the resulting TSHUT gave CRU module,let it reset the entire chip,
> or via GPIO give PMIC.
> 
> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> ---
>  drivers/thermal/Kconfig            |   9 +
>  drivers/thermal/Makefile           |   1 +
>  drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 679 insertions(+)
>  create mode 100644 drivers/thermal/rockchip_thermal.c
> 
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index f9a1386..a00aa1e 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
>  	  Enable this to plug the SPEAr thermal sensor driver into the Linux
>  	  thermal framework.
>  
> +config ROCKCHIP_THERMAL
> +	tristate "Rockchip thermal driver"
> +	depends on ARCH_ROCKCHIP
> +	help
> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
> +	  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 RCAR_THERMAL
>  	tristate "Renesas R-Car thermal driver"
>  	depends on ARCH_SHMOBILE || COMPILE_TEST
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index de0636a..b48b817 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
>  
>  # platform thermal drivers
>  obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
>  obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
>  obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
>  obj-y				+= samsung/
> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
> new file mode 100644
> index 0000000..011f387
> --- /dev/null
> +++ b/drivers/thermal/rockchip_thermal.c
> @@ -0,0 +1,669 @@
> +/*
> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
> + *
> + * 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/clk.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/cpu_cooling.h>
> +#include "thermal_core.h"

Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
sufficient?

> +
> +enum rockchip_thermal_trip {
> +	ROCKCHIP_TRIP_PASSIVE,
> +	ROCKCHIP_TRIP_CRITICAL,
> +	ROCKCHIP_TRIP_NUM,
> +};
> +

Why do you need your own trip types?

> +struct rockchip_thermal_data {
> +	const struct rockchip_tsadc_platform_data *pdata;
> +	struct thermal_zone_device *tz;
> +	struct thermal_cooling_device *cdev;
> +	enum thermal_device_mode mode;
> +	void __iomem *regs;
> +
> +	signed long temp_passive;
> +	signed long temp_critical;
> +	signed long temp_force_shut;
> +	signed long alarm_temp;
> +	signed long last_temp;
> +	bool irq_enabled;
> +	int irq;
> +	struct clk *clk;
> +	struct clk *pclk;
> +};
> +
> +struct rockchip_tsadc_platform_data {
> +	u8 irq_en;
> +	signed long temp_passive;
> +	signed long temp_critical;
> +	signed long temp_force_shut;
> +	int passive_delay;
> +	int polling_delay;
> +
> +	int (*irq_handle)(void __iomem *reg);
> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
> +	int (*control)(void __iomem *reg, bool on);
> +	u32 (*code_to_temp)(int temp);
> +	u32 (*temp_to_code)(int temp);
> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
> +};
> +
> +/*TSADC V2 Sensor info define:*/
> +#define TSADCV2_AUTO_CON			0x04
> +#define TSADCV2_INT_EN				0x08
> +#define TSADCV2_INT_PD				0x0c
> +#define TSADCV2_DATA1				0x24
> +#define TSADCV2_COMP1_INT			0x34
> +#define TSADCV2_COMP1_SHUT			0x44
> +#define TSADCV2_AUTO_PERIOD			0x68
> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
> +
> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
> +#define TSADCV2_AUTO_EN				(1 << 0)
> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
> +

The above bits can be defined with BIT() macro, right? Something like:
+#define TSADCV2_INT_SRC1_STATUS			BIT(1)


> +#define TSADCV2_DATA_MASK			0xfff
> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
> +
> +struct tsadc_table {
> +	int code;
> +	int temp;
> +};
> +
> +static const struct tsadc_table v2_code_table[] = {
> +	{TSADCV2_DATA_MASK, -40},
> +	{3800, -40},
> +	{3792, -35},
> +	{3783, -30},
> +	{3774, -25},
> +	{3765, -20},
> +	{3756, -15},
> +	{3747, -10},
> +	{3737, -5},
> +	{3728, 0},
> +	{3718, 5},
> +	{3708, 10},
> +	{3698, 15},
> +	{3688, 20},
> +	{3678, 25},
> +	{3667, 30},
> +	{3656, 35},
> +	{3645, 40},
> +	{3634, 45},
> +	{3623, 50},
> +	{3611, 55},
> +	{3600, 60},
> +	{3588, 65},
> +	{3575, 70},
> +	{3563, 75},
> +	{3550, 80},
> +	{3537, 85},
> +	{3524, 90},
> +	{3510, 95},
> +	{3496, 100},
> +	{3482, 105},
> +	{3467, 110},
> +	{3452, 115},
> +	{3437, 120},
> +	{3421, 125},
> +	{0, 125},
> +};
> +
> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);

Why do you need to clear bit 8? Why hardcoded?

> +
> +	return 0;
> +}
> +
> +static u32 rk_tsadcv2_temp_to_code(int temp)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
> +		if (temp <= v2_code_table[i].temp && temp >
> +		    v2_code_table[i - 1].temp)
> +			return v2_code_table[i].code;
> +	}
> +
> +	return 0;
> +}
> +
> +static u32 rk_tsadcv2_code_to_temp(int code)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
> +		if (code <= v2_code_table[i].code && code >
> +		    v2_code_table[i + 1].code){
> +			return v2_code_table[i].temp;
> +		}
> +	}
> +
> +	return 0;
> +}

I know the table is not something too big, but considering it is ordered
by either ADC value code or by temp, at least one of the above searching function
may be more efficient, right?

> +
> +static int rk_tsadcv2_initialize(void __iomem *regs,
> +				 signed long temp_force_shut)
> +{
> +	int shutdown_value;
> +
> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
> +	/* Enable measurements at ~ 10 Hz */

Does it leave the sampling clock at 10Hz? Is this clock exposed via
clock framework?

> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
> +		       TSADCV2_AUTO_PERIOD_HT);
> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
> +		       TSADCV2_INT_EN);
> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
> +		       TSADCV2_AUTO_CON);
> +
> +	return 0;
> +}
> +
> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
> +{
> +	u32 val;
> +
> +	if (on) {
> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
> +	} else {
> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
> +			       regs + TSADCV2_AUTO_CON);
> +	}
> +
> +	return 0;
> +}
> +
> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
> +{
> +	int alarm_value;
> +
> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
> +}
> +
> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
> +	.irq_en = 1,
> +	.temp_passive = 85000,
> +	.temp_critical = 100000,
> +	.temp_force_shut = 120000,
> +	.passive_delay = 2000,
> +	.polling_delay = 1000,
> +	.irq_handle = rk_tsadcv2_irq_handle,
> +	.initialize = rk_tsadcv2_initialize,
> +	.control = rk_tsadcv2_control,
> +	.code_to_temp = rk_tsadcv2_code_to_temp,
> +	.temp_to_code = rk_tsadcv2_temp_to_code,
> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
> +};

shall the above struct be also static?

> +
> +static const struct of_device_id of_rockchip_thermal_match[] = {
> +	{
> +		.compatible = "rockchip,rk3288-tsadc",
> +		.data = (void *)&rk3288_tsadc_data,
> +	},
> +	{ /* end */ },
> +};
> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
> +
> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
> +				    signed long alarm_temp)
> +{
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +
> +	data->alarm_temp = alarm_temp;
> +	if (p_tsadc_data->set_alarm_temp)
> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
> +}
> +
> +static int rockchip_get_temp(struct thermal_zone_device *tz,
> +			     unsigned long *temp)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +	u32 val;
> +
> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
> +	*temp = p_tsadc_data->code_to_temp(val);
> +
> +	/* Update alarm value to next higher trip point */
> +	if (data->alarm_temp == data->temp_passive && *temp >=
> +	    data->temp_passive)
> +		rockchip_set_alarm_temp(data, data->temp_critical);
> +
> +	if (data->alarm_temp == data->temp_critical && *temp <
> +	    data->temp_passive) {
> +		rockchip_set_alarm_temp(data, data->temp_passive);
> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
> +			data->alarm_temp / 1000);
> +	}
> +
> +	if (*temp != data->last_temp) {
> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
> +		data->last_temp = *temp;
> +	}
> +
> +	/* Reenable alarm IRQ if temperature below alarm temperature */
> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
> +		data->irq_enabled = true;
> +		enable_irq(data->irq);
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
> +{
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +
> +	if (p_tsadc_data->initialize)
> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
> +	rockchip_set_alarm_temp(data, data->temp_passive);
> +
> +	return 0;
> +}
> +
> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
> +				     bool on)
> +{
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +
> +	if (p_tsadc_data->control)
> +		p_tsadc_data->control(data->regs, on);
> +
> +	if (on) {
> +		data->irq_enabled = true;
> +		data->mode = THERMAL_DEVICE_ENABLED;
> +	} else {
> +		data->irq_enabled = false;
> +		data->mode = THERMAL_DEVICE_DISABLED;
> +	}
> +}
> +
> +static int rockchip_get_mode(struct thermal_zone_device *tz,
> +			     enum thermal_device_mode *mode)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +
> +	*mode = data->mode;
> +
> +	return 0;
> +}
> +
> +static int rockchip_set_mode(struct thermal_zone_device *tz,
> +			     enum thermal_device_mode mode)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +
> +	if (mode == THERMAL_DEVICE_ENABLED) {
> +		tz->polling_delay = p_tsadc_data->polling_delay;
> +		tz->passive_delay = p_tsadc_data->passive_delay;
> +		if (!data->irq_enabled) {
> +			data->irq_enabled = true;
> +			enable_irq(data->irq);
> +		}
> +	} else {
> +		tz->polling_delay = 0;
> +		tz->passive_delay = 0;
> +		if (data->irq_enabled) {
> +			disable_irq(data->irq);
> +			data->irq_enabled = false;
> +		}
> +	}
> +
> +	data->mode = mode;
> +	thermal_zone_device_update(tz);
> +
> +	return 0;
> +}
> +
> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
> +				  enum thermal_trip_type *type)
> +{
> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
> +		 THERMAL_TRIP_CRITICAL;
> +
> +	return 0;
> +}
> +
> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
> +				  unsigned long *temp)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +
> +	*temp = data->temp_critical;
> +
> +	return 0;
> +}
> +
> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
> +				  unsigned long *temp)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +
> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
> +		 data->temp_critical;
> +
> +	return 0;
> +}
> +
> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
> +				  unsigned long temp)
> +{
> +	struct rockchip_thermal_data *data = tz->devdata;
> +
> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
> +		return -EPERM;
> +
> +	data->temp_passive = temp;
> +	rockchip_set_alarm_temp(data, temp);
> +
> +	return 0;
> +}
> +
> +static int rockchip_bind(struct thermal_zone_device *tz,
> +			 struct thermal_cooling_device *cdev)
> +{
> +	int ret;
> +
> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
> +					       THERMAL_NO_LIMIT,
> +					       THERMAL_NO_LIMIT);
> +	if (ret) {
> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> +			tz->type, cdev->type, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_unbind(struct thermal_zone_device *tz,
> +			   struct thermal_cooling_device *cdev)
> +{
> +	int ret;
> +
> +	ret = thermal_zone_unbind_cooling_device(tz,
> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
> +	if (ret) {
> +		dev_err(&tz->device,
> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
> +			cdev->type, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}

The method of binding and unbinding used above requires you to check if
you are binding to the right cdev. If in your system you register more
than one cdev, say someone loads the power supply core, which in turns
register a cooling device for charging, your thermal zone will bind it
to TRIP_PASSIVE. It will happen to any cooling device that eventually
gets registered to the thermal framework. Is that the desired outcome?

If not, you may want to compare the paramenter cdev to your data->cdev.

> +
> +static struct thermal_zone_device_ops rockchip_tz_ops = {
> +	.bind = rockchip_bind,
> +	.unbind = rockchip_unbind,
> +	.get_temp = rockchip_get_temp,
> +	.get_mode = rockchip_get_mode,
> +	.set_mode = rockchip_set_mode,
> +	.get_trip_type = rockchip_get_trip_type,
> +	.get_trip_temp = rockchip_get_trip_temp,
> +	.get_crit_temp = rockchip_get_crit_temp,
> +	.set_trip_temp = rockchip_set_trip_temp,
> +};
> +
> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
> +{
> +	struct rockchip_thermal_data *data = data;
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> +
> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
> +		data->alarm_temp / 1000);
> +
> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
> +		p_tsadc_data->irq_handle(data->regs);
> +
> +	thermal_zone_device_update(data->tz);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int rockchip_thermal_probe(struct platform_device *pdev)
> +{
> +	struct rockchip_thermal_data *data;
> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
> +	struct cpumask clip_cpus;
> +	struct resource *res;
> +	const struct of_device_id *match;
> +	int ret, temp;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
> +			    GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(data->regs)) {
> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
> +			data->regs);
> +		return PTR_ERR(data->regs);
> +	}
> +
> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
> +	if (!match)
> +		return -ENXIO;
> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
> +	if (!data->pdata)
> +		return -EINVAL;
> +	p_tsadc_data = data->pdata;
> +
> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
> +	if (IS_ERR(data->clk)) {
> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
> +		return PTR_ERR(data->clk);
> +	}
> +
> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
> +	if (IS_ERR(data->pclk)) {
> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
> +		return PTR_ERR(data->pclk);
> +	}
> +
> +	/*
> +	* Use a default of 10KHz for the converter clock.
> +	* This may become user-configurable in the future.
> +	*/
> +	ret = clk_set_rate(data->clk, 10000);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(data->clk);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
> +		goto err_clk;
> +	}
> +
> +	ret = clk_prepare_enable(data->pclk);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to enable pclk\n");
> +		goto err_pclk;
> +	}
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
> +		dev_warn(&pdev->dev,
> +			 "Missing default passive temp property in the DT.\n");
> +		data->temp_passive = p_tsadc_data->temp_passive;
> +	} else {
> +		data->temp_passive = temp;
> +	}
> +
> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
> +		dev_warn(&pdev->dev,
> +			 "Missing default critical temp property in the DT.\n");
> +		data->temp_critical = p_tsadc_data->temp_critical;
> +	} else {
> +		data->temp_critical = temp;
> +	}
> +
> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
> +		dev_warn(&pdev->dev,
> +			 "Missing default force shut down temp property in the DT.\n");
> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
> +	} else {
> +		data->temp_force_shut = temp;
> +	}
> +
> +	cpumask_set_cpu(0, &clip_cpus);
> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
> +	if (IS_ERR(data->cdev)) {
> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
> +		goto disable_clk;
> +	}
> +
> +	data->tz = thermal_zone_device_register("rockchip_thermal",
> +						ROCKCHIP_TRIP_NUM,
> +						0, data,
> +						&rockchip_tz_ops, NULL,
> +						p_tsadc_data->passive_delay,
> +						p_tsadc_data->polling_delay);
> +
> +	if (IS_ERR(data->tz)) {
> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
> +		goto fail_cpufreq_register;
> +	}
> +
> +	if (p_tsadc_data->irq_en) {
> +		data->irq = platform_get_irq(pdev, 0);
> +		if (data->irq < 0) {
> +			dev_err(&pdev->dev, "no irq resource?\n");
> +			goto fail_irq;
> +		}
> +
> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
> +				rockchip_thermal_alarm_irq_thread,
> +				IRQF_ONESHOT, "rockchip_thermal", data);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev,
> +				"failed to request tsadc irq: %d\n", ret);
> +			goto fail_thermal_unregister;
> +		}
> +	}
> +
> +	rockchip_thermal_initialize(data);
> +	rockchip_thermal_control(data, true);
> +
> +	return 0;
> +
> +fail_thermal_unregister:
> +	thermal_zone_device_unregister(data->tz);
> +fail_irq:
> +fail_cpufreq_register:
> +	cpufreq_cooling_unregister(data->cdev);
> +disable_clk:
> +err_pclk:
> +	clk_disable_unprepare(data->pclk);
> +err_clk:
> +	clk_disable_unprepare(data->clk);
> +
> +	return ret;
> +}
> +
> +static int rockchip_thermal_remove(struct platform_device *pdev)
> +{
> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> +
> +	rockchip_thermal_control(data, false);
> +
> +	thermal_zone_device_unregister(data->tz);
> +	cpufreq_cooling_unregister(data->cdev);
> +	cpufreq_cooling_unregister(data->cdev);
> +

The above call is duplicated.

> +	clk_disable_unprepare(data->clk);
> +	clk_disable_unprepare(data->pclk);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int rockchip_thermal_suspend(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> +
> +	rockchip_thermal_control(data, false);
> +
> +	return 0;
> +}
> +
> +static int rockchip_thermal_resume(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> +
> +	rockchip_thermal_initialize(data);
> +	rockchip_thermal_control(data, true);
> +
> +	return 0;
> +}

Would you need to manage your clocks too in the suspend resume path
(data->clk and data->pclk)?

> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
> +
> +static struct platform_driver rockchip_thermal_driver = {
> +	.driver = {
> +		   .name = "rockchip-thermal",
> +		   .owner = THIS_MODULE,
> +		   .pm = &rockchip_thermal_pm_ops,
> +		   .of_match_table = of_rockchip_thermal_match,
> +		   },
> +	.probe = rockchip_thermal_probe,
> +	.remove = rockchip_thermal_remove,
> +};
> +
> +module_platform_driver(rockchip_thermal_driver);
> +
> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
> +MODULE_AUTHOR("Rockchip, Inc.");
> +MODULE_LICENSE("GPL");

Your file header states GPL version two. Thus I suppose you meant:
+MODULE_LICENSE("GPL v2");

right?

Check include/linux/module.h for further clarifications.

> +MODULE_ALIAS("platform:rockchip-thermal");
> -- 
> 1.9.1
> 
> 

BR,

Eduardo Valentin

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 0/4] Rockchip soc thermal driver
@ 2014-09-03  2:10 ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-03  2:10 UTC (permalink / raw)
  To: heiko, rui.zhang, edubezval
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, linux-doc,
	huangtao, cf, dianders, dtor, zyw, addy.ke, dmitry.torokhov,
	Caesar Wang

Changes in v4:
        * address comments from Jonathan Cameron,huangtao and zhaoyifeng:
        - this series thermal driver still be put in driver/thermal/
        - modify the thermal driver description.

Changes in v3:(add dts configure)
        * address comments from Dmitry Torokhov and Arnd Bergmann:
        - fix clock-names in rockchip-thermal.txt
        - remove rockchip_thermal_control() in rockchip_set_mode()
        - fix some code style.
        - add dts configure.

Changes in v2:
        * address comments from Heiko Stubner:
        - fix dt-bindings in rockchip-thermal.txt
        - remove Author mark
        - rename TSADC_XXX->TSADCV2_XXX,it eill ready to merge compatible other SoCs.
        - fix a identation
        - remove clk_set_rate(),it's no necessary.
        - fix the SIMPLE_DEV_PM_OPS() function  style.

Tested on rk3288 SDK board

Caesar Wang (4):
  thermal: rockchip: add driver for thermal
  dt-bindings: document Rockchip thermal
  ARM: dts: add main Thermal info to rk3288
  ARM: dts: enable Thermal on rk3288-evb board

 .../bindings/thermal/rockchip-thermal.txt          |  20 +
 arch/arm/boot/dts/rk3288-evb.dtsi                  |   7 +
 arch/arm/boot/dts/rk3288.dtsi                      |  18 +
 drivers/thermal/Kconfig                            |   9 +
 drivers/thermal/Makefile                           |   1 +
 drivers/thermal/rockchip_thermal.c                 | 669 +++++++++++++++++++++
 6 files changed, 724 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
 create mode 100644 drivers/thermal/rockchip_thermal.c

-- 
1.9.1



^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 0/4] Rockchip soc thermal driver
@ 2014-09-03  2:10 ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-03  2:10 UTC (permalink / raw)
  To: linux-arm-kernel

Changes in v4:
        * address comments from Jonathan Cameron,huangtao and zhaoyifeng:
        - this series thermal driver still be put in driver/thermal/
        - modify the thermal driver description.

Changes in v3:(add dts configure)
        * address comments from Dmitry Torokhov and Arnd Bergmann:
        - fix clock-names in rockchip-thermal.txt
        - remove rockchip_thermal_control() in rockchip_set_mode()
        - fix some code style.
        - add dts configure.

Changes in v2:
        * address comments from Heiko Stubner:
        - fix dt-bindings in rockchip-thermal.txt
        - remove Author mark
        - rename TSADC_XXX->TSADCV2_XXX,it eill ready to merge compatible other SoCs.
        - fix a identation
        - remove clk_set_rate(),it's no necessary.
        - fix the SIMPLE_DEV_PM_OPS() function  style.

Tested on rk3288 SDK board

Caesar Wang (4):
  thermal: rockchip: add driver for thermal
  dt-bindings: document Rockchip thermal
  ARM: dts: add main Thermal info to rk3288
  ARM: dts: enable Thermal on rk3288-evb board

 .../bindings/thermal/rockchip-thermal.txt          |  20 +
 arch/arm/boot/dts/rk3288-evb.dtsi                  |   7 +
 arch/arm/boot/dts/rk3288.dtsi                      |  18 +
 drivers/thermal/Kconfig                            |   9 +
 drivers/thermal/Makefile                           |   1 +
 drivers/thermal/rockchip_thermal.c                 | 669 +++++++++++++++++++++
 6 files changed, 724 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
 create mode 100644 drivers/thermal/rockchip_thermal.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 1/4] thermal: rockchip: add driver for thermal
  2014-09-03  2:10 ` Caesar Wang
@ 2014-09-03  2:10   ` Caesar Wang
  -1 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-03  2:10 UTC (permalink / raw)
  To: heiko, rui.zhang, edubezval
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, linux-doc,
	huangtao, cf, dianders, dtor, zyw, addy.ke, dmitry.torokhov,
	Caesar Wang, zhaoyifeng

Thermal is TS-ADC Controller module supports
user-defined mode and automatic mode.

User-defined mode refers,TSADC all the control signals entirely by
software writing to register for direct control.

Automaic mode refers to the module automatically poll TSADC output,
and the results were checked.If you find that the temperature High
in a period of time,an interrupt is generated to the processor
down-measures taken;if the temperature over a period of time High,
the resulting TSHUT gave CRU module,let it reset the entire chip,
or via GPIO give PMIC.

Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
---
 drivers/thermal/Kconfig            |   9 +
 drivers/thermal/Makefile           |   1 +
 drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
 3 files changed, 679 insertions(+)
 create mode 100644 drivers/thermal/rockchip_thermal.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f9a1386..a00aa1e 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -133,6 +133,15 @@ config SPEAR_THERMAL
 	  Enable this to plug the SPEAr thermal sensor driver into the Linux
 	  thermal framework.
 
+config ROCKCHIP_THERMAL
+	tristate "Rockchip thermal driver"
+	depends on ARCH_ROCKCHIP
+	help
+	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
+	  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 RCAR_THERMAL
 	tristate "Renesas R-Car thermal driver"
 	depends on ARCH_SHMOBILE || COMPILE_TEST
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index de0636a..b48b817 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
 
 # platform thermal drivers
 obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
+obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
 obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
 obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
 obj-y				+= samsung/
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
new file mode 100644
index 0000000..011f387
--- /dev/null
+++ b/drivers/thermal/rockchip_thermal.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * 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/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/cpu_cooling.h>
+#include "thermal_core.h"
+
+enum rockchip_thermal_trip {
+	ROCKCHIP_TRIP_PASSIVE,
+	ROCKCHIP_TRIP_CRITICAL,
+	ROCKCHIP_TRIP_NUM,
+};
+
+struct rockchip_thermal_data {
+	const struct rockchip_tsadc_platform_data *pdata;
+	struct thermal_zone_device *tz;
+	struct thermal_cooling_device *cdev;
+	enum thermal_device_mode mode;
+	void __iomem *regs;
+
+	signed long temp_passive;
+	signed long temp_critical;
+	signed long temp_force_shut;
+	signed long alarm_temp;
+	signed long last_temp;
+	bool irq_enabled;
+	int irq;
+	struct clk *clk;
+	struct clk *pclk;
+};
+
+struct rockchip_tsadc_platform_data {
+	u8 irq_en;
+	signed long temp_passive;
+	signed long temp_critical;
+	signed long temp_force_shut;
+	int passive_delay;
+	int polling_delay;
+
+	int (*irq_handle)(void __iomem *reg);
+	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
+	int (*control)(void __iomem *reg, bool on);
+	u32 (*code_to_temp)(int temp);
+	u32 (*temp_to_code)(int temp);
+	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
+};
+
+/*TSADC V2 Sensor info define:*/
+#define TSADCV2_AUTO_CON			0x04
+#define TSADCV2_INT_EN				0x08
+#define TSADCV2_INT_PD				0x0c
+#define TSADCV2_DATA1				0x24
+#define TSADCV2_COMP1_INT			0x34
+#define TSADCV2_COMP1_SHUT			0x44
+#define TSADCV2_AUTO_PERIOD			0x68
+#define TSADCV2_AUTO_PERIOD_HT			0x6c
+
+#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
+#define TSADCV2_AUTO_EN				(1 << 0)
+#define TSADCV2_AUTO_DISABLE			~(1 << 0)
+#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
+#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
+#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
+#define TSADCV2_INT_SRC1_EN			(1 << 1)
+#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
+#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
+
+#define TSADCV2_DATA_MASK			0xfff
+#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
+#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
+#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
+#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
+#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
+#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
+
+struct tsadc_table {
+	int code;
+	int temp;
+};
+
+static const struct tsadc_table v2_code_table[] = {
+	{TSADCV2_DATA_MASK, -40},
+	{3800, -40},
+	{3792, -35},
+	{3783, -30},
+	{3774, -25},
+	{3765, -20},
+	{3756, -15},
+	{3747, -10},
+	{3737, -5},
+	{3728, 0},
+	{3718, 5},
+	{3708, 10},
+	{3698, 15},
+	{3688, 20},
+	{3678, 25},
+	{3667, 30},
+	{3656, 35},
+	{3645, 40},
+	{3634, 45},
+	{3623, 50},
+	{3611, 55},
+	{3600, 60},
+	{3588, 65},
+	{3575, 70},
+	{3563, 75},
+	{3550, 80},
+	{3537, 85},
+	{3524, 90},
+	{3510, 95},
+	{3496, 100},
+	{3482, 105},
+	{3467, 110},
+	{3452, 115},
+	{3437, 120},
+	{3421, 125},
+	{0, 125},
+};
+
+static int rk_tsadcv2_irq_handle(void __iomem *regs)
+{
+	u32 val;
+
+	val = readl_relaxed(regs + TSADCV2_INT_PD);
+	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
+
+	return 0;
+}
+
+static u32 rk_tsadcv2_temp_to_code(int temp)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
+		if (temp <= v2_code_table[i].temp && temp >
+		    v2_code_table[i - 1].temp)
+			return v2_code_table[i].code;
+	}
+
+	return 0;
+}
+
+static u32 rk_tsadcv2_code_to_temp(int code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
+		if (code <= v2_code_table[i].code && code >
+		    v2_code_table[i + 1].code){
+			return v2_code_table[i].temp;
+		}
+	}
+
+	return 0;
+}
+
+static int rk_tsadcv2_initialize(void __iomem *regs,
+				 signed long temp_force_shut)
+{
+	int shutdown_value;
+
+	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
+	/* Enable measurements at ~ 10 Hz */
+	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
+	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
+	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
+		       TSADCV2_AUTO_PERIOD_HT);
+	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
+	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
+		       TSADCV2_HIGHT_INT_DEBOUNCE);
+	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
+		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
+	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
+		       TSADCV2_INT_EN);
+	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
+		       TSADCV2_AUTO_CON);
+
+	return 0;
+}
+
+static int rk_tsadcv2_control(void __iomem *regs, bool on)
+{
+	u32 val;
+
+	if (on) {
+		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
+		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
+	} else {
+		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
+		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
+			       regs + TSADCV2_AUTO_CON);
+	}
+
+	return 0;
+}
+
+static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
+{
+	int alarm_value;
+
+	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
+	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
+}
+
+struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
+	.irq_en = 1,
+	.temp_passive = 85000,
+	.temp_critical = 100000,
+	.temp_force_shut = 120000,
+	.passive_delay = 2000,
+	.polling_delay = 1000,
+	.irq_handle = rk_tsadcv2_irq_handle,
+	.initialize = rk_tsadcv2_initialize,
+	.control = rk_tsadcv2_control,
+	.code_to_temp = rk_tsadcv2_code_to_temp,
+	.temp_to_code = rk_tsadcv2_temp_to_code,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
+};
+
+static const struct of_device_id of_rockchip_thermal_match[] = {
+	{
+		.compatible = "rockchip,rk3288-tsadc",
+		.data = (void *)&rk3288_tsadc_data,
+	},
+	{ /* end */ },
+};
+MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
+
+static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
+				    signed long alarm_temp)
+{
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+
+	data->alarm_temp = alarm_temp;
+	if (p_tsadc_data->set_alarm_temp)
+		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
+}
+
+static int rockchip_get_temp(struct thermal_zone_device *tz,
+			     unsigned long *temp)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+	u32 val;
+
+	val = readl_relaxed(data->regs + TSADCV2_DATA1);
+	*temp = p_tsadc_data->code_to_temp(val);
+
+	/* Update alarm value to next higher trip point */
+	if (data->alarm_temp == data->temp_passive && *temp >=
+	    data->temp_passive)
+		rockchip_set_alarm_temp(data, data->temp_critical);
+
+	if (data->alarm_temp == data->temp_critical && *temp <
+	    data->temp_passive) {
+		rockchip_set_alarm_temp(data, data->temp_passive);
+		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
+			data->alarm_temp / 1000);
+	}
+
+	if (*temp != data->last_temp) {
+		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
+		data->last_temp = *temp;
+	}
+
+	/* Reenable alarm IRQ if temperature below alarm temperature */
+	if (!data->irq_enabled && *temp < data->alarm_temp) {
+		data->irq_enabled = true;
+		enable_irq(data->irq);
+	}
+
+	return 0;
+}
+
+static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
+{
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+
+	if (p_tsadc_data->initialize)
+		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
+	rockchip_set_alarm_temp(data, data->temp_passive);
+
+	return 0;
+}
+
+static void rockchip_thermal_control(struct rockchip_thermal_data *data,
+				     bool on)
+{
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+
+	if (p_tsadc_data->control)
+		p_tsadc_data->control(data->regs, on);
+
+	if (on) {
+		data->irq_enabled = true;
+		data->mode = THERMAL_DEVICE_ENABLED;
+	} else {
+		data->irq_enabled = false;
+		data->mode = THERMAL_DEVICE_DISABLED;
+	}
+}
+
+static int rockchip_get_mode(struct thermal_zone_device *tz,
+			     enum thermal_device_mode *mode)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+
+	*mode = data->mode;
+
+	return 0;
+}
+
+static int rockchip_set_mode(struct thermal_zone_device *tz,
+			     enum thermal_device_mode mode)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+
+	if (mode == THERMAL_DEVICE_ENABLED) {
+		tz->polling_delay = p_tsadc_data->polling_delay;
+		tz->passive_delay = p_tsadc_data->passive_delay;
+		if (!data->irq_enabled) {
+			data->irq_enabled = true;
+			enable_irq(data->irq);
+		}
+	} else {
+		tz->polling_delay = 0;
+		tz->passive_delay = 0;
+		if (data->irq_enabled) {
+			disable_irq(data->irq);
+			data->irq_enabled = false;
+		}
+	}
+
+	data->mode = mode;
+	thermal_zone_device_update(tz);
+
+	return 0;
+}
+
+static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
+				  enum thermal_trip_type *type)
+{
+	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
+		 THERMAL_TRIP_CRITICAL;
+
+	return 0;
+}
+
+static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
+				  unsigned long *temp)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+
+	*temp = data->temp_critical;
+
+	return 0;
+}
+
+static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
+				  unsigned long *temp)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+
+	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
+		 data->temp_critical;
+
+	return 0;
+}
+
+static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
+				  unsigned long temp)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+
+	if (trip == ROCKCHIP_TRIP_CRITICAL)
+		return -EPERM;
+
+	data->temp_passive = temp;
+	rockchip_set_alarm_temp(data, temp);
+
+	return 0;
+}
+
+static int rockchip_bind(struct thermal_zone_device *tz,
+			 struct thermal_cooling_device *cdev)
+{
+	int ret;
+
+	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
+					       THERMAL_NO_LIMIT,
+					       THERMAL_NO_LIMIT);
+	if (ret) {
+		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
+			tz->type, cdev->type, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_unbind(struct thermal_zone_device *tz,
+			   struct thermal_cooling_device *cdev)
+{
+	int ret;
+
+	ret = thermal_zone_unbind_cooling_device(tz,
+						 ROCKCHIP_TRIP_PASSIVE, cdev);
+	if (ret) {
+		dev_err(&tz->device,
+			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
+			cdev->type, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct thermal_zone_device_ops rockchip_tz_ops = {
+	.bind = rockchip_bind,
+	.unbind = rockchip_unbind,
+	.get_temp = rockchip_get_temp,
+	.get_mode = rockchip_get_mode,
+	.set_mode = rockchip_set_mode,
+	.get_trip_type = rockchip_get_trip_type,
+	.get_trip_temp = rockchip_get_trip_temp,
+	.get_crit_temp = rockchip_get_crit_temp,
+	.set_trip_temp = rockchip_set_trip_temp,
+};
+
+static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
+{
+	struct rockchip_thermal_data *data = data;
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+
+	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
+		data->alarm_temp / 1000);
+
+	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
+		p_tsadc_data->irq_handle(data->regs);
+
+	thermal_zone_device_update(data->tz);
+
+	return IRQ_HANDLED;
+}
+
+static int rockchip_thermal_probe(struct platform_device *pdev)
+{
+	struct rockchip_thermal_data *data;
+	const struct rockchip_tsadc_platform_data *p_tsadc_data;
+	struct cpumask clip_cpus;
+	struct resource *res;
+	const struct of_device_id *match;
+	int ret, temp;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->regs)) {
+		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
+			data->regs);
+		return PTR_ERR(data->regs);
+	}
+
+	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
+	if (!match)
+		return -ENXIO;
+	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
+	if (!data->pdata)
+		return -EINVAL;
+	p_tsadc_data = data->pdata;
+
+	data->clk = devm_clk_get(&pdev->dev, "tsadc");
+	if (IS_ERR(data->clk)) {
+		dev_err(&pdev->dev, "failed to get tsadc clock\n");
+		return PTR_ERR(data->clk);
+	}
+
+	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
+	if (IS_ERR(data->pclk)) {
+		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
+		return PTR_ERR(data->pclk);
+	}
+
+	/*
+	* Use a default of 10KHz for the converter clock.
+	* This may become user-configurable in the future.
+	*/
+	ret = clk_set_rate(data->clk, 10000);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(data->clk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable converter clock\n");
+		goto err_clk;
+	}
+
+	ret = clk_prepare_enable(data->pclk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable pclk\n");
+		goto err_pclk;
+	}
+
+	platform_set_drvdata(pdev, data);
+
+	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
+		dev_warn(&pdev->dev,
+			 "Missing default passive temp property in the DT.\n");
+		data->temp_passive = p_tsadc_data->temp_passive;
+	} else {
+		data->temp_passive = temp;
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
+		dev_warn(&pdev->dev,
+			 "Missing default critical temp property in the DT.\n");
+		data->temp_critical = p_tsadc_data->temp_critical;
+	} else {
+		data->temp_critical = temp;
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
+		dev_warn(&pdev->dev,
+			 "Missing default force shut down temp property in the DT.\n");
+		data->temp_force_shut = p_tsadc_data->temp_force_shut;
+	} else {
+		data->temp_force_shut = temp;
+	}
+
+	cpumask_set_cpu(0, &clip_cpus);
+	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
+	if (IS_ERR(data->cdev)) {
+		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
+		goto disable_clk;
+	}
+
+	data->tz = thermal_zone_device_register("rockchip_thermal",
+						ROCKCHIP_TRIP_NUM,
+						0, data,
+						&rockchip_tz_ops, NULL,
+						p_tsadc_data->passive_delay,
+						p_tsadc_data->polling_delay);
+
+	if (IS_ERR(data->tz)) {
+		dev_err(&pdev->dev, "failed to register thermal zone device\n");
+		goto fail_cpufreq_register;
+	}
+
+	if (p_tsadc_data->irq_en) {
+		data->irq = platform_get_irq(pdev, 0);
+		if (data->irq < 0) {
+			dev_err(&pdev->dev, "no irq resource?\n");
+			goto fail_irq;
+		}
+
+		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
+				rockchip_thermal_alarm_irq_thread,
+				IRQF_ONESHOT, "rockchip_thermal", data);
+		if (ret < 0) {
+			dev_err(&pdev->dev,
+				"failed to request tsadc irq: %d\n", ret);
+			goto fail_thermal_unregister;
+		}
+	}
+
+	rockchip_thermal_initialize(data);
+	rockchip_thermal_control(data, true);
+
+	return 0;
+
+fail_thermal_unregister:
+	thermal_zone_device_unregister(data->tz);
+fail_irq:
+fail_cpufreq_register:
+	cpufreq_cooling_unregister(data->cdev);
+disable_clk:
+err_pclk:
+	clk_disable_unprepare(data->pclk);
+err_clk:
+	clk_disable_unprepare(data->clk);
+
+	return ret;
+}
+
+static int rockchip_thermal_remove(struct platform_device *pdev)
+{
+	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
+
+	rockchip_thermal_control(data, false);
+
+	thermal_zone_device_unregister(data->tz);
+	cpufreq_cooling_unregister(data->cdev);
+	cpufreq_cooling_unregister(data->cdev);
+
+	clk_disable_unprepare(data->clk);
+	clk_disable_unprepare(data->pclk);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_thermal_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
+
+	rockchip_thermal_control(data, false);
+
+	return 0;
+}
+
+static int rockchip_thermal_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
+
+	rockchip_thermal_initialize(data);
+	rockchip_thermal_control(data, true);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
+			 rockchip_thermal_suspend, rockchip_thermal_resume);
+
+static struct platform_driver rockchip_thermal_driver = {
+	.driver = {
+		   .name = "rockchip-thermal",
+		   .owner = THIS_MODULE,
+		   .pm = &rockchip_thermal_pm_ops,
+		   .of_match_table = of_rockchip_thermal_match,
+		   },
+	.probe = rockchip_thermal_probe,
+	.remove = rockchip_thermal_remove,
+};
+
+module_platform_driver(rockchip_thermal_driver);
+
+MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
+MODULE_AUTHOR("Rockchip, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rockchip-thermal");
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v4 1/4] thermal: rockchip: add driver for thermal
@ 2014-09-03  2:10   ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-03  2:10 UTC (permalink / raw)
  To: linux-arm-kernel

Thermal is TS-ADC Controller module supports
user-defined mode and automatic mode.

User-defined mode refers,TSADC all the control signals entirely by
software writing to register for direct control.

Automaic mode refers to the module automatically poll TSADC output,
and the results were checked.If you find that the temperature High
in a period of time,an interrupt is generated to the processor
down-measures taken;if the temperature over a period of time High,
the resulting TSHUT gave CRU module,let it reset the entire chip,
or via GPIO give PMIC.

Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
---
 drivers/thermal/Kconfig            |   9 +
 drivers/thermal/Makefile           |   1 +
 drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
 3 files changed, 679 insertions(+)
 create mode 100644 drivers/thermal/rockchip_thermal.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f9a1386..a00aa1e 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -133,6 +133,15 @@ config SPEAR_THERMAL
 	  Enable this to plug the SPEAr thermal sensor driver into the Linux
 	  thermal framework.
 
+config ROCKCHIP_THERMAL
+	tristate "Rockchip thermal driver"
+	depends on ARCH_ROCKCHIP
+	help
+	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
+	  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 RCAR_THERMAL
 	tristate "Renesas R-Car thermal driver"
 	depends on ARCH_SHMOBILE || COMPILE_TEST
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index de0636a..b48b817 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
 
 # platform thermal drivers
 obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
+obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
 obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
 obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
 obj-y				+= samsung/
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
new file mode 100644
index 0000000..011f387
--- /dev/null
+++ b/drivers/thermal/rockchip_thermal.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * 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/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/cpu_cooling.h>
+#include "thermal_core.h"
+
+enum rockchip_thermal_trip {
+	ROCKCHIP_TRIP_PASSIVE,
+	ROCKCHIP_TRIP_CRITICAL,
+	ROCKCHIP_TRIP_NUM,
+};
+
+struct rockchip_thermal_data {
+	const struct rockchip_tsadc_platform_data *pdata;
+	struct thermal_zone_device *tz;
+	struct thermal_cooling_device *cdev;
+	enum thermal_device_mode mode;
+	void __iomem *regs;
+
+	signed long temp_passive;
+	signed long temp_critical;
+	signed long temp_force_shut;
+	signed long alarm_temp;
+	signed long last_temp;
+	bool irq_enabled;
+	int irq;
+	struct clk *clk;
+	struct clk *pclk;
+};
+
+struct rockchip_tsadc_platform_data {
+	u8 irq_en;
+	signed long temp_passive;
+	signed long temp_critical;
+	signed long temp_force_shut;
+	int passive_delay;
+	int polling_delay;
+
+	int (*irq_handle)(void __iomem *reg);
+	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
+	int (*control)(void __iomem *reg, bool on);
+	u32 (*code_to_temp)(int temp);
+	u32 (*temp_to_code)(int temp);
+	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
+};
+
+/*TSADC V2 Sensor info define:*/
+#define TSADCV2_AUTO_CON			0x04
+#define TSADCV2_INT_EN				0x08
+#define TSADCV2_INT_PD				0x0c
+#define TSADCV2_DATA1				0x24
+#define TSADCV2_COMP1_INT			0x34
+#define TSADCV2_COMP1_SHUT			0x44
+#define TSADCV2_AUTO_PERIOD			0x68
+#define TSADCV2_AUTO_PERIOD_HT			0x6c
+
+#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
+#define TSADCV2_AUTO_EN				(1 << 0)
+#define TSADCV2_AUTO_DISABLE			~(1 << 0)
+#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
+#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
+#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
+#define TSADCV2_INT_SRC1_EN			(1 << 1)
+#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
+#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
+
+#define TSADCV2_DATA_MASK			0xfff
+#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
+#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
+#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
+#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
+#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
+#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
+
+struct tsadc_table {
+	int code;
+	int temp;
+};
+
+static const struct tsadc_table v2_code_table[] = {
+	{TSADCV2_DATA_MASK, -40},
+	{3800, -40},
+	{3792, -35},
+	{3783, -30},
+	{3774, -25},
+	{3765, -20},
+	{3756, -15},
+	{3747, -10},
+	{3737, -5},
+	{3728, 0},
+	{3718, 5},
+	{3708, 10},
+	{3698, 15},
+	{3688, 20},
+	{3678, 25},
+	{3667, 30},
+	{3656, 35},
+	{3645, 40},
+	{3634, 45},
+	{3623, 50},
+	{3611, 55},
+	{3600, 60},
+	{3588, 65},
+	{3575, 70},
+	{3563, 75},
+	{3550, 80},
+	{3537, 85},
+	{3524, 90},
+	{3510, 95},
+	{3496, 100},
+	{3482, 105},
+	{3467, 110},
+	{3452, 115},
+	{3437, 120},
+	{3421, 125},
+	{0, 125},
+};
+
+static int rk_tsadcv2_irq_handle(void __iomem *regs)
+{
+	u32 val;
+
+	val = readl_relaxed(regs + TSADCV2_INT_PD);
+	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
+
+	return 0;
+}
+
+static u32 rk_tsadcv2_temp_to_code(int temp)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
+		if (temp <= v2_code_table[i].temp && temp >
+		    v2_code_table[i - 1].temp)
+			return v2_code_table[i].code;
+	}
+
+	return 0;
+}
+
+static u32 rk_tsadcv2_code_to_temp(int code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
+		if (code <= v2_code_table[i].code && code >
+		    v2_code_table[i + 1].code){
+			return v2_code_table[i].temp;
+		}
+	}
+
+	return 0;
+}
+
+static int rk_tsadcv2_initialize(void __iomem *regs,
+				 signed long temp_force_shut)
+{
+	int shutdown_value;
+
+	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
+	/* Enable measurements at ~ 10 Hz */
+	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
+	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
+	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
+		       TSADCV2_AUTO_PERIOD_HT);
+	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
+	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
+		       TSADCV2_HIGHT_INT_DEBOUNCE);
+	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
+		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
+	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
+		       TSADCV2_INT_EN);
+	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
+		       TSADCV2_AUTO_CON);
+
+	return 0;
+}
+
+static int rk_tsadcv2_control(void __iomem *regs, bool on)
+{
+	u32 val;
+
+	if (on) {
+		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
+		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
+	} else {
+		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
+		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
+			       regs + TSADCV2_AUTO_CON);
+	}
+
+	return 0;
+}
+
+static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
+{
+	int alarm_value;
+
+	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
+	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
+}
+
+struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
+	.irq_en = 1,
+	.temp_passive = 85000,
+	.temp_critical = 100000,
+	.temp_force_shut = 120000,
+	.passive_delay = 2000,
+	.polling_delay = 1000,
+	.irq_handle = rk_tsadcv2_irq_handle,
+	.initialize = rk_tsadcv2_initialize,
+	.control = rk_tsadcv2_control,
+	.code_to_temp = rk_tsadcv2_code_to_temp,
+	.temp_to_code = rk_tsadcv2_temp_to_code,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
+};
+
+static const struct of_device_id of_rockchip_thermal_match[] = {
+	{
+		.compatible = "rockchip,rk3288-tsadc",
+		.data = (void *)&rk3288_tsadc_data,
+	},
+	{ /* end */ },
+};
+MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
+
+static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
+				    signed long alarm_temp)
+{
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+
+	data->alarm_temp = alarm_temp;
+	if (p_tsadc_data->set_alarm_temp)
+		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
+}
+
+static int rockchip_get_temp(struct thermal_zone_device *tz,
+			     unsigned long *temp)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+	u32 val;
+
+	val = readl_relaxed(data->regs + TSADCV2_DATA1);
+	*temp = p_tsadc_data->code_to_temp(val);
+
+	/* Update alarm value to next higher trip point */
+	if (data->alarm_temp == data->temp_passive && *temp >=
+	    data->temp_passive)
+		rockchip_set_alarm_temp(data, data->temp_critical);
+
+	if (data->alarm_temp == data->temp_critical && *temp <
+	    data->temp_passive) {
+		rockchip_set_alarm_temp(data, data->temp_passive);
+		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
+			data->alarm_temp / 1000);
+	}
+
+	if (*temp != data->last_temp) {
+		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
+		data->last_temp = *temp;
+	}
+
+	/* Reenable alarm IRQ if temperature below alarm temperature */
+	if (!data->irq_enabled && *temp < data->alarm_temp) {
+		data->irq_enabled = true;
+		enable_irq(data->irq);
+	}
+
+	return 0;
+}
+
+static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
+{
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+
+	if (p_tsadc_data->initialize)
+		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
+	rockchip_set_alarm_temp(data, data->temp_passive);
+
+	return 0;
+}
+
+static void rockchip_thermal_control(struct rockchip_thermal_data *data,
+				     bool on)
+{
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+
+	if (p_tsadc_data->control)
+		p_tsadc_data->control(data->regs, on);
+
+	if (on) {
+		data->irq_enabled = true;
+		data->mode = THERMAL_DEVICE_ENABLED;
+	} else {
+		data->irq_enabled = false;
+		data->mode = THERMAL_DEVICE_DISABLED;
+	}
+}
+
+static int rockchip_get_mode(struct thermal_zone_device *tz,
+			     enum thermal_device_mode *mode)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+
+	*mode = data->mode;
+
+	return 0;
+}
+
+static int rockchip_set_mode(struct thermal_zone_device *tz,
+			     enum thermal_device_mode mode)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+
+	if (mode == THERMAL_DEVICE_ENABLED) {
+		tz->polling_delay = p_tsadc_data->polling_delay;
+		tz->passive_delay = p_tsadc_data->passive_delay;
+		if (!data->irq_enabled) {
+			data->irq_enabled = true;
+			enable_irq(data->irq);
+		}
+	} else {
+		tz->polling_delay = 0;
+		tz->passive_delay = 0;
+		if (data->irq_enabled) {
+			disable_irq(data->irq);
+			data->irq_enabled = false;
+		}
+	}
+
+	data->mode = mode;
+	thermal_zone_device_update(tz);
+
+	return 0;
+}
+
+static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
+				  enum thermal_trip_type *type)
+{
+	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
+		 THERMAL_TRIP_CRITICAL;
+
+	return 0;
+}
+
+static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
+				  unsigned long *temp)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+
+	*temp = data->temp_critical;
+
+	return 0;
+}
+
+static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
+				  unsigned long *temp)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+
+	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
+		 data->temp_critical;
+
+	return 0;
+}
+
+static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
+				  unsigned long temp)
+{
+	struct rockchip_thermal_data *data = tz->devdata;
+
+	if (trip == ROCKCHIP_TRIP_CRITICAL)
+		return -EPERM;
+
+	data->temp_passive = temp;
+	rockchip_set_alarm_temp(data, temp);
+
+	return 0;
+}
+
+static int rockchip_bind(struct thermal_zone_device *tz,
+			 struct thermal_cooling_device *cdev)
+{
+	int ret;
+
+	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
+					       THERMAL_NO_LIMIT,
+					       THERMAL_NO_LIMIT);
+	if (ret) {
+		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
+			tz->type, cdev->type, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_unbind(struct thermal_zone_device *tz,
+			   struct thermal_cooling_device *cdev)
+{
+	int ret;
+
+	ret = thermal_zone_unbind_cooling_device(tz,
+						 ROCKCHIP_TRIP_PASSIVE, cdev);
+	if (ret) {
+		dev_err(&tz->device,
+			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
+			cdev->type, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct thermal_zone_device_ops rockchip_tz_ops = {
+	.bind = rockchip_bind,
+	.unbind = rockchip_unbind,
+	.get_temp = rockchip_get_temp,
+	.get_mode = rockchip_get_mode,
+	.set_mode = rockchip_set_mode,
+	.get_trip_type = rockchip_get_trip_type,
+	.get_trip_temp = rockchip_get_trip_temp,
+	.get_crit_temp = rockchip_get_crit_temp,
+	.set_trip_temp = rockchip_set_trip_temp,
+};
+
+static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
+{
+	struct rockchip_thermal_data *data = data;
+	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
+
+	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
+		data->alarm_temp / 1000);
+
+	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
+		p_tsadc_data->irq_handle(data->regs);
+
+	thermal_zone_device_update(data->tz);
+
+	return IRQ_HANDLED;
+}
+
+static int rockchip_thermal_probe(struct platform_device *pdev)
+{
+	struct rockchip_thermal_data *data;
+	const struct rockchip_tsadc_platform_data *p_tsadc_data;
+	struct cpumask clip_cpus;
+	struct resource *res;
+	const struct of_device_id *match;
+	int ret, temp;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->regs)) {
+		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
+			data->regs);
+		return PTR_ERR(data->regs);
+	}
+
+	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
+	if (!match)
+		return -ENXIO;
+	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
+	if (!data->pdata)
+		return -EINVAL;
+	p_tsadc_data = data->pdata;
+
+	data->clk = devm_clk_get(&pdev->dev, "tsadc");
+	if (IS_ERR(data->clk)) {
+		dev_err(&pdev->dev, "failed to get tsadc clock\n");
+		return PTR_ERR(data->clk);
+	}
+
+	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
+	if (IS_ERR(data->pclk)) {
+		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
+		return PTR_ERR(data->pclk);
+	}
+
+	/*
+	* Use a default of 10KHz for the converter clock.
+	* This may become user-configurable in the future.
+	*/
+	ret = clk_set_rate(data->clk, 10000);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(data->clk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable converter clock\n");
+		goto err_clk;
+	}
+
+	ret = clk_prepare_enable(data->pclk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable pclk\n");
+		goto err_pclk;
+	}
+
+	platform_set_drvdata(pdev, data);
+
+	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
+		dev_warn(&pdev->dev,
+			 "Missing default passive temp property in the DT.\n");
+		data->temp_passive = p_tsadc_data->temp_passive;
+	} else {
+		data->temp_passive = temp;
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
+		dev_warn(&pdev->dev,
+			 "Missing default critical temp property in the DT.\n");
+		data->temp_critical = p_tsadc_data->temp_critical;
+	} else {
+		data->temp_critical = temp;
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
+		dev_warn(&pdev->dev,
+			 "Missing default force shut down temp property in the DT.\n");
+		data->temp_force_shut = p_tsadc_data->temp_force_shut;
+	} else {
+		data->temp_force_shut = temp;
+	}
+
+	cpumask_set_cpu(0, &clip_cpus);
+	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
+	if (IS_ERR(data->cdev)) {
+		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
+		goto disable_clk;
+	}
+
+	data->tz = thermal_zone_device_register("rockchip_thermal",
+						ROCKCHIP_TRIP_NUM,
+						0, data,
+						&rockchip_tz_ops, NULL,
+						p_tsadc_data->passive_delay,
+						p_tsadc_data->polling_delay);
+
+	if (IS_ERR(data->tz)) {
+		dev_err(&pdev->dev, "failed to register thermal zone device\n");
+		goto fail_cpufreq_register;
+	}
+
+	if (p_tsadc_data->irq_en) {
+		data->irq = platform_get_irq(pdev, 0);
+		if (data->irq < 0) {
+			dev_err(&pdev->dev, "no irq resource?\n");
+			goto fail_irq;
+		}
+
+		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
+				rockchip_thermal_alarm_irq_thread,
+				IRQF_ONESHOT, "rockchip_thermal", data);
+		if (ret < 0) {
+			dev_err(&pdev->dev,
+				"failed to request tsadc irq: %d\n", ret);
+			goto fail_thermal_unregister;
+		}
+	}
+
+	rockchip_thermal_initialize(data);
+	rockchip_thermal_control(data, true);
+
+	return 0;
+
+fail_thermal_unregister:
+	thermal_zone_device_unregister(data->tz);
+fail_irq:
+fail_cpufreq_register:
+	cpufreq_cooling_unregister(data->cdev);
+disable_clk:
+err_pclk:
+	clk_disable_unprepare(data->pclk);
+err_clk:
+	clk_disable_unprepare(data->clk);
+
+	return ret;
+}
+
+static int rockchip_thermal_remove(struct platform_device *pdev)
+{
+	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
+
+	rockchip_thermal_control(data, false);
+
+	thermal_zone_device_unregister(data->tz);
+	cpufreq_cooling_unregister(data->cdev);
+	cpufreq_cooling_unregister(data->cdev);
+
+	clk_disable_unprepare(data->clk);
+	clk_disable_unprepare(data->pclk);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_thermal_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
+
+	rockchip_thermal_control(data, false);
+
+	return 0;
+}
+
+static int rockchip_thermal_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
+
+	rockchip_thermal_initialize(data);
+	rockchip_thermal_control(data, true);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
+			 rockchip_thermal_suspend, rockchip_thermal_resume);
+
+static struct platform_driver rockchip_thermal_driver = {
+	.driver = {
+		   .name = "rockchip-thermal",
+		   .owner = THIS_MODULE,
+		   .pm = &rockchip_thermal_pm_ops,
+		   .of_match_table = of_rockchip_thermal_match,
+		   },
+	.probe = rockchip_thermal_probe,
+	.remove = rockchip_thermal_remove,
+};
+
+module_platform_driver(rockchip_thermal_driver);
+
+MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
+MODULE_AUTHOR("Rockchip, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rockchip-thermal");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-03  2:10 ` Caesar Wang
@ 2014-09-03  2:10   ` Caesar Wang
  -1 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-03  2:10 UTC (permalink / raw)
  To: heiko, rui.zhang, edubezval
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, linux-doc,
	huangtao, cf, dianders, dtor, zyw, addy.ke, dmitry.torokhov,
	Caesar Wang, zhaoyifeng

This add the necessary binding documentation for the thermal
found on Rockchip SoCs

Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
---
 .../devicetree/bindings/thermal/rockchip-thermal.txt | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/thermal/rockchip-thermal.txt

diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
new file mode 100644
index 0000000..1ed4d4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
@@ -0,0 +1,20 @@
+* Temperature Sensor ADC (TSADC) on rockchip SoCs
+
+Required properties:
+- compatible: "rockchip,rk3288-tsadc"
+- reg: physical base address of the controller and length of memory mapped
+       region.
+- interrupts: The interrupt number to the cpu. The interrupt specifier format
+	      depends on the interrupt controller.
+- clocks: Must contain an entry for each entry in clock-names.
+- clock-names: Shall be "tsadc" for the converter-clock, and "apb_pclk" for
+	       the peripheral clock.
+
+Example:
+tsadc: tsadc@ff280000 {
+	compatible = "rockchip,rk3288-tsadc";
+	reg = <0xff280000 0x100>;
+	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
+	clock-names = "tsadc", "apb_pclk";
+};
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-03  2:10   ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-03  2:10 UTC (permalink / raw)
  To: linux-arm-kernel

This add the necessary binding documentation for the thermal
found on Rockchip SoCs

Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
---
 .../devicetree/bindings/thermal/rockchip-thermal.txt | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/thermal/rockchip-thermal.txt

diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
new file mode 100644
index 0000000..1ed4d4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
@@ -0,0 +1,20 @@
+* Temperature Sensor ADC (TSADC) on rockchip SoCs
+
+Required properties:
+- compatible: "rockchip,rk3288-tsadc"
+- reg: physical base address of the controller and length of memory mapped
+       region.
+- interrupts: The interrupt number to the cpu. The interrupt specifier format
+	      depends on the interrupt controller.
+- clocks: Must contain an entry for each entry in clock-names.
+- clock-names: Shall be "tsadc" for the converter-clock, and "apb_pclk" for
+	       the peripheral clock.
+
+Example:
+tsadc: tsadc at ff280000 {
+	compatible = "rockchip,rk3288-tsadc";
+	reg = <0xff280000 0x100>;
+	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
+	clock-names = "tsadc", "apb_pclk";
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v4 3/4] ARM: dts: add main Thermal info to rk3288
  2014-09-03  2:10 ` Caesar Wang
@ 2014-09-03  2:10   ` Caesar Wang
  -1 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-03  2:10 UTC (permalink / raw)
  To: heiko, rui.zhang, edubezval
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, linux-doc,
	huangtao, cf, dianders, dtor, zyw, addy.ke, dmitry.torokhov,
	Caesar Wang

Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
---
 arch/arm/boot/dts/rk3288.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 36be7bb..3d672e3 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -224,6 +224,17 @@
 		status = "disabled";
 	};
 
+	tsadc: tsadc@ff280000 {
+		compatible = "rockchip,rk3288-tsadc";
+		reg = <0xff280000 0x100>;
+		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
+		clock-names = "tsadc", "apb_pclk";
+		pinctrl-names = "default";
+		pinctrl-1 = <&tsadc_int>;
+		status = "disabled";
+	};
+
 	/* NOTE: ohci@ff520000 doesn't actually work on hardware */
 
 	usb_hsic: usb@ff5c0000 {
@@ -611,5 +622,12 @@
 				rockchip,pins = <5 15 3 &pcfg_pull_none>;
 			};
 		};
+
+		tsadc {
+			tsadc_int: tsadc-int {
+				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
+			};
+		};
+
 	};
 };
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v4 3/4] ARM: dts: add main Thermal info to rk3288
@ 2014-09-03  2:10   ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-03  2:10 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
---
 arch/arm/boot/dts/rk3288.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 36be7bb..3d672e3 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -224,6 +224,17 @@
 		status = "disabled";
 	};
 
+	tsadc: tsadc at ff280000 {
+		compatible = "rockchip,rk3288-tsadc";
+		reg = <0xff280000 0x100>;
+		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
+		clock-names = "tsadc", "apb_pclk";
+		pinctrl-names = "default";
+		pinctrl-1 = <&tsadc_int>;
+		status = "disabled";
+	};
+
 	/* NOTE: ohci at ff520000 doesn't actually work on hardware */
 
 	usb_hsic: usb at ff5c0000 {
@@ -611,5 +622,12 @@
 				rockchip,pins = <5 15 3 &pcfg_pull_none>;
 			};
 		};
+
+		tsadc {
+			tsadc_int: tsadc-int {
+				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
+			};
+		};
+
 	};
 };
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v4 4/4] ARM: dts: enable Thermal on rk3288-evb board
  2014-09-03  2:10 ` Caesar Wang
@ 2014-09-03  2:10   ` Caesar Wang
  -1 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-03  2:10 UTC (permalink / raw)
  To: heiko, rui.zhang, edubezval
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, linux-doc,
	huangtao, cf, dianders, dtor, zyw, addy.ke, dmitry.torokhov,
	Caesar Wang

Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
---
 arch/arm/boot/dts/rk3288-evb.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi
index 2964370..fe85dde 100644
--- a/arch/arm/boot/dts/rk3288-evb.dtsi
+++ b/arch/arm/boot/dts/rk3288-evb.dtsi
@@ -101,6 +101,13 @@
 	status = "okay";
 };
 
+&tsadc {
+	passive-temp = <80>;
+	critical-temp = <100>;
+	force-shut-temp = <120>;
+	status = "okay";
+};
+
 &pinctrl {
 	buttons {
 		pwrbtn: pwrbtn {
-- 
1.9.1



^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH v4 4/4] ARM: dts: enable Thermal on rk3288-evb board
@ 2014-09-03  2:10   ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-03  2:10 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
---
 arch/arm/boot/dts/rk3288-evb.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi
index 2964370..fe85dde 100644
--- a/arch/arm/boot/dts/rk3288-evb.dtsi
+++ b/arch/arm/boot/dts/rk3288-evb.dtsi
@@ -101,6 +101,13 @@
 	status = "okay";
 };
 
+&tsadc {
+	passive-temp = <80>;
+	critical-temp = <100>;
+	force-shut-temp = <120>;
+	status = "okay";
+};
+
 &pinctrl {
 	buttons {
 		pwrbtn: pwrbtn {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-03  2:10   ` Caesar Wang
@ 2014-09-03  8:07     ` Heiko Stübner
  -1 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-03  8:07 UTC (permalink / raw)
  To: Caesar Wang
  Cc: rui.zhang, edubezval, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov, zhaoyifeng

Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> This add the necessary binding documentation for the thermal
> found on Rockchip SoCs
> 
> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> ---
>  .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> 
> diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new file
> mode 100644
> index 0000000..1ed4d4c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> @@ -0,0 +1,20 @@
> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> +
> +Required properties:
> +- compatible: "rockchip,rk3288-tsadc"
> +- reg: physical base address of the controller and length of memory mapped
> +       region.
> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> format +	      depends on the interrupt controller.
> +- clocks: Must contain an entry for each entry in clock-names.
> +- clock-names: Shall be "tsadc" for the converter-clock, and "apb_pclk" for
> +	       the peripheral clock.

You're using the passive-temp, critical-temp and force-shut-temp properties in 
your driver without declaring them here.

But more importantly, please use the generic trip-points for this. I guess it 
shouldn't be a problem to introduce a "forced-shutdown" trippoint [0] for the 
additional trip-point you have - thermal maintainers, please shout if I'm 
wrong :-)


Heiko


[0] in a separate patch, changing
- thermal_trip_type enum in include/linux/thermal.h
- trip_types mapping in drivers/thermal/of-thermal.c
- Documentation/devicetree/bindings/thermal/thermal.txt

> +
> +Example:
> +tsadc: tsadc@ff280000 {
> +	compatible = "rockchip,rk3288-tsadc";
> +	reg = <0xff280000 0x100>;
> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> +	clock-names = "tsadc", "apb_pclk";
> +};


^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-03  8:07     ` Heiko Stübner
  0 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-03  8:07 UTC (permalink / raw)
  To: linux-arm-kernel

Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> This add the necessary binding documentation for the thermal
> found on Rockchip SoCs
> 
> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> ---
>  .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> 
> diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new file
> mode 100644
> index 0000000..1ed4d4c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> @@ -0,0 +1,20 @@
> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> +
> +Required properties:
> +- compatible: "rockchip,rk3288-tsadc"
> +- reg: physical base address of the controller and length of memory mapped
> +       region.
> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> format +	      depends on the interrupt controller.
> +- clocks: Must contain an entry for each entry in clock-names.
> +- clock-names: Shall be "tsadc" for the converter-clock, and "apb_pclk" for
> +	       the peripheral clock.

You're using the passive-temp, critical-temp and force-shut-temp properties in 
your driver without declaring them here.

But more importantly, please use the generic trip-points for this. I guess it 
shouldn't be a problem to introduce a "forced-shutdown" trippoint [0] for the 
additional trip-point you have - thermal maintainers, please shout if I'm 
wrong :-)


Heiko


[0] in a separate patch, changing
- thermal_trip_type enum in include/linux/thermal.h
- trip_types mapping in drivers/thermal/of-thermal.c
- Documentation/devicetree/bindings/thermal/thermal.txt

> +
> +Example:
> +tsadc: tsadc at ff280000 {
> +	compatible = "rockchip,rk3288-tsadc";
> +	reg = <0xff280000 0x100>;
> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> +	clock-names = "tsadc", "apb_pclk";
> +};

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-03  8:07     ` Heiko Stübner
@ 2014-09-04  1:02       ` Caesar Wang
  -1 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-04  1:02 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: rui.zhang, edubezval, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov, zhaoyifeng


在 2014年09月03日 16:07, Heiko Stübner 写道:
> Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
>> This add the necessary binding documentation for the thermal
>> found on Rockchip SoCs
>>
>> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
>> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>> ---
>>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
>> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
>>   create mode 100644
>> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>>
>> diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new file
>> mode 100644
>> index 0000000..1ed4d4c
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>> @@ -0,0 +1,20 @@
>> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
>> +
>> +Required properties:
>> +- compatible: "rockchip,rk3288-tsadc"
>> +- reg: physical base address of the controller and length of memory mapped
>> +       region.
>> +- interrupts: The interrupt number to the cpu. The interrupt specifier
>> format +	      depends on the interrupt controller.
>> +- clocks: Must contain an entry for each entry in clock-names.
>> +- clock-names: Shall be "tsadc" for the converter-clock, and "apb_pclk" for
>> +	       the peripheral clock.
> You're using the passive-temp, critical-temp and force-shut-temp properties in
> your driver without declaring them here.

frankly,the about are need be declared. but  there are 4 types[0] for 
trip in thermal framework,
there is no force-shut for me. So I want to change it three additional 
properties in [PATCH V4 4/4],


[0]
{
     THERMAL_TRIP_CRITICAL,
     THERMAL_TRIP_HOT,
     THERMAL_TRIP_PASSIVE,
     THERMAL_TRIP_ACTIVE,
}

> But more importantly, please use the generic trip-points for this. I guess it
> shouldn't be a problem to introduce a "forced-shutdown" trippoint [0] for the
> additional trip-point you have - thermal maintainers, please shout if I'm
> wrong :-)

It's a good option.
I can send a patch,but I don't know whether the thermal maintainers will 
accept it.

Maybe,they have a better way to suggest it.:-)


PS:I will sent a new patch If I still have no received their suggestions 
in two days.

>
> Heiko
>
>
> [0] in a separate patch, changing
> - thermal_trip_type enum in include/linux/thermal.h
> - trip_types mapping in drivers/thermal/of-thermal.c
> - Documentation/devicetree/bindings/thermal/thermal.txt
>
>> +
>> +Example:
>> +tsadc: tsadc@ff280000 {
>> +	compatible = "rockchip,rk3288-tsadc";
>> +	reg = <0xff280000 0x100>;
>> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
>> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
>> +	clock-names = "tsadc", "apb_pclk";
>> +};
>
>
>

-- 
Best regards,
Caesar



^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-04  1:02       ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-04  1:02 UTC (permalink / raw)
  To: linux-arm-kernel


? 2014?09?03? 16:07, Heiko St?bner ??:
> Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
>> This add the necessary binding documentation for the thermal
>> found on Rockchip SoCs
>>
>> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
>> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>> ---
>>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
>> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
>>   create mode 100644
>> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>>
>> diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new file
>> mode 100644
>> index 0000000..1ed4d4c
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>> @@ -0,0 +1,20 @@
>> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
>> +
>> +Required properties:
>> +- compatible: "rockchip,rk3288-tsadc"
>> +- reg: physical base address of the controller and length of memory mapped
>> +       region.
>> +- interrupts: The interrupt number to the cpu. The interrupt specifier
>> format +	      depends on the interrupt controller.
>> +- clocks: Must contain an entry for each entry in clock-names.
>> +- clock-names: Shall be "tsadc" for the converter-clock, and "apb_pclk" for
>> +	       the peripheral clock.
> You're using the passive-temp, critical-temp and force-shut-temp properties in
> your driver without declaring them here.

frankly,the about are need be declared. but  there are 4 types[0] for 
trip in thermal framework,
there is no force-shut for me. So I want to change it three additional 
properties in [PATCH V4 4/4],


[0]
{
     THERMAL_TRIP_CRITICAL,
     THERMAL_TRIP_HOT,
     THERMAL_TRIP_PASSIVE,
     THERMAL_TRIP_ACTIVE,
}

> But more importantly, please use the generic trip-points for this. I guess it
> shouldn't be a problem to introduce a "forced-shutdown" trippoint [0] for the
> additional trip-point you have - thermal maintainers, please shout if I'm
> wrong :-)

It's a good option.
I can send a patch,but I don't know whether the thermal maintainers will 
accept it.

Maybe,they have a better way to suggest it.:-)


PS:I will sent a new patch If I still have no received their suggestions 
in two days.

>
> Heiko
>
>
> [0] in a separate patch, changing
> - thermal_trip_type enum in include/linux/thermal.h
> - trip_types mapping in drivers/thermal/of-thermal.c
> - Documentation/devicetree/bindings/thermal/thermal.txt
>
>> +
>> +Example:
>> +tsadc: tsadc at ff280000 {
>> +	compatible = "rockchip,rk3288-tsadc";
>> +	reg = <0xff280000 0x100>;
>> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
>> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
>> +	clock-names = "tsadc", "apb_pclk";
>> +};
>
>
>

-- 
Best regards,
Caesar

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 1/4] thermal: rockchip: add driver for thermal
  2014-09-03  2:10   ` Caesar Wang
@ 2014-09-04 17:06     ` Dmitry Torokhov
  -1 siblings, 0 replies; 65+ messages in thread
From: Dmitry Torokhov @ 2014-09-04 17:06 UTC (permalink / raw)
  To: Caesar Wang
  Cc: heiko, rui.zhang, edubezval, linux-kernel, linux-pm,
	linux-arm-kernel, devicetree, linux-doc, huangtao, cf, dianders,
	zyw, addy.ke, zhaoyifeng

Hi Caesar,

On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
> +static int rockchip_thermal_remove(struct platform_device *pdev)
> +{
> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> +
> +	rockchip_thermal_control(data, false);
> +
> +	thermal_zone_device_unregister(data->tz);
> +	cpufreq_cooling_unregister(data->cdev);
> +	cpufreq_cooling_unregister(data->cdev);

It looks like we are unregistering the same cooling device one too many times.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 1/4] thermal: rockchip: add driver for thermal
@ 2014-09-04 17:06     ` Dmitry Torokhov
  0 siblings, 0 replies; 65+ messages in thread
From: Dmitry Torokhov @ 2014-09-04 17:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Caesar,

On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
> +static int rockchip_thermal_remove(struct platform_device *pdev)
> +{
> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> +
> +	rockchip_thermal_control(data, false);
> +
> +	thermal_zone_device_unregister(data->tz);
> +	cpufreq_cooling_unregister(data->cdev);
> +	cpufreq_cooling_unregister(data->cdev);

It looks like we are unregistering the same cooling device one too many times.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 1/4] thermal: rockchip: add driver for thermal
  2014-09-04 17:06     ` Dmitry Torokhov
@ 2014-09-05  0:33       ` Caesar Wang
  -1 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-05  0:33 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: heiko, rui.zhang, edubezval, linux-kernel, linux-pm,
	linux-arm-kernel, devicetree, linux-doc, huangtao, cf, dianders,
	zyw, addy.ke, zhaoyifeng


在 2014年09月05日 01:06, Dmitry Torokhov 写道:
> Hi Caesar,
>
> On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
>> +static int rockchip_thermal_remove(struct platform_device *pdev)
>> +{
>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>> +
>> +	rockchip_thermal_control(data, false);
>> +
>> +	thermal_zone_device_unregister(data->tz);
>> +	cpufreq_cooling_unregister(data->cdev);
>> +	cpufreq_cooling_unregister(data->cdev);
> It looks like we are unregistering the same cooling device one too many times.
>
> Thanks.
>
yes,I made a stupid mistake.  Thanks~

-- 
Best regards,
Caesar



^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 1/4] thermal: rockchip: add driver for thermal
@ 2014-09-05  0:33       ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-05  0:33 UTC (permalink / raw)
  To: linux-arm-kernel


? 2014?09?05? 01:06, Dmitry Torokhov ??:
> Hi Caesar,
>
> On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
>> +static int rockchip_thermal_remove(struct platform_device *pdev)
>> +{
>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>> +
>> +	rockchip_thermal_control(data, false);
>> +
>> +	thermal_zone_device_unregister(data->tz);
>> +	cpufreq_cooling_unregister(data->cdev);
>> +	cpufreq_cooling_unregister(data->cdev);
> It looks like we are unregistering the same cooling device one too many times.
>
> Thanks.
>
yes,I made a stupid mistake.  Thanks~

-- 
Best regards,
Caesar

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-04  1:02       ` Caesar Wang
@ 2014-09-09  2:27         ` Zhang Rui
  -1 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-09  2:27 UTC (permalink / raw)
  To: Caesar Wang
  Cc: Heiko Stübner, edubezval, linux-kernel, linux-pm,
	linux-arm-kernel, devicetree, linux-doc, huangtao, cf, dianders,
	dtor, zyw, addy.ke, dmitry.torokhov, zhaoyifeng

On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> 在 2014年09月03日 16:07, Heiko Stübner 写道:
> > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> >> This add the necessary binding documentation for the thermal
> >> found on Rockchip SoCs
> >>
> >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> >> ---
> >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> >>   create mode 100644
> >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >>
> >> diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new file
> >> mode 100644
> >> index 0000000..1ed4d4c
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> @@ -0,0 +1,20 @@
> >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> >> +
> >> +Required properties:
> >> +- compatible: "rockchip,rk3288-tsadc"
> >> +- reg: physical base address of the controller and length of memory mapped
> >> +       region.
> >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> >> format +	      depends on the interrupt controller.
> >> +- clocks: Must contain an entry for each entry in clock-names.
> >> +- clock-names: Shall be "tsadc" for the converter-clock, and "apb_pclk" for
> >> +	       the peripheral clock.
> > You're using the passive-temp, critical-temp and force-shut-temp properties in
> > your driver without declaring them here.
> 
> frankly,the about are need be declared. but  there are 4 types[0] for 
> trip in thermal framework,
> there is no force-shut for me. So I want to change it three additional 
> properties in [PATCH V4 4/4],
> 
> 
> [0]
> {
>      THERMAL_TRIP_CRITICAL,
>      THERMAL_TRIP_HOT,
>      THERMAL_TRIP_PASSIVE,
>      THERMAL_TRIP_ACTIVE,
> }
> 
this sounds reasonable to me.

> > But more importantly, please use the generic trip-points for this. I guess it
> > shouldn't be a problem to introduce a "forced-shutdown" trippoint [0] for the
> > additional trip-point you have - thermal maintainers, please shout if I'm
> > wrong :-)
> 
what is the difference between a critical trip point and a
"forced-shutdown" trip point?
Thermal core will do a shutdown in case the critical trip point is
triggered.

thanks,
rui
> It's a good option.
> I can send a patch,but I don't know whether the thermal maintainers will 
> accept it.
> 
> Maybe,they have a better way to suggest it.:-)
> 
> 
> PS:I will sent a new patch If I still have no received their suggestions 
> in two days.
> 
> >
> > Heiko
> >
> >
> > [0] in a separate patch, changing
> > - thermal_trip_type enum in include/linux/thermal.h
> > - trip_types mapping in drivers/thermal/of-thermal.c
> > - Documentation/devicetree/bindings/thermal/thermal.txt
> >
> >> +
> >> +Example:
> >> +tsadc: tsadc@ff280000 {
> >> +	compatible = "rockchip,rk3288-tsadc";
> >> +	reg = <0xff280000 0x100>;
> >> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> >> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> >> +	clock-names = "tsadc", "apb_pclk";
> >> +};
> >
> >
> >
> 



^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-09  2:27         ` Zhang Rui
  0 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-09  2:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> ? 2014?09?03? 16:07, Heiko St?bner ??:
> > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> >> This add the necessary binding documentation for the thermal
> >> found on Rockchip SoCs
> >>
> >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> >> ---
> >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> >>   create mode 100644
> >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >>
> >> diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new file
> >> mode 100644
> >> index 0000000..1ed4d4c
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> @@ -0,0 +1,20 @@
> >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> >> +
> >> +Required properties:
> >> +- compatible: "rockchip,rk3288-tsadc"
> >> +- reg: physical base address of the controller and length of memory mapped
> >> +       region.
> >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> >> format +	      depends on the interrupt controller.
> >> +- clocks: Must contain an entry for each entry in clock-names.
> >> +- clock-names: Shall be "tsadc" for the converter-clock, and "apb_pclk" for
> >> +	       the peripheral clock.
> > You're using the passive-temp, critical-temp and force-shut-temp properties in
> > your driver without declaring them here.
> 
> frankly,the about are need be declared. but  there are 4 types[0] for 
> trip in thermal framework,
> there is no force-shut for me. So I want to change it three additional 
> properties in [PATCH V4 4/4],
> 
> 
> [0]
> {
>      THERMAL_TRIP_CRITICAL,
>      THERMAL_TRIP_HOT,
>      THERMAL_TRIP_PASSIVE,
>      THERMAL_TRIP_ACTIVE,
> }
> 
this sounds reasonable to me.

> > But more importantly, please use the generic trip-points for this. I guess it
> > shouldn't be a problem to introduce a "forced-shutdown" trippoint [0] for the
> > additional trip-point you have - thermal maintainers, please shout if I'm
> > wrong :-)
> 
what is the difference between a critical trip point and a
"forced-shutdown" trip point?
Thermal core will do a shutdown in case the critical trip point is
triggered.

thanks,
rui
> It's a good option.
> I can send a patch,but I don't know whether the thermal maintainers will 
> accept it.
> 
> Maybe,they have a better way to suggest it.:-)
> 
> 
> PS:I will sent a new patch If I still have no received their suggestions 
> in two days.
> 
> >
> > Heiko
> >
> >
> > [0] in a separate patch, changing
> > - thermal_trip_type enum in include/linux/thermal.h
> > - trip_types mapping in drivers/thermal/of-thermal.c
> > - Documentation/devicetree/bindings/thermal/thermal.txt
> >
> >> +
> >> +Example:
> >> +tsadc: tsadc at ff280000 {
> >> +	compatible = "rockchip,rk3288-tsadc";
> >> +	reg = <0xff280000 0x100>;
> >> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> >> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> >> +	clock-names = "tsadc", "apb_pclk";
> >> +};
> >
> >
> >
> 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-09  2:27         ` Zhang Rui
  (?)
@ 2014-09-09 11:35           ` Heiko Stübner
  -1 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-09 11:35 UTC (permalink / raw)
  To: Zhang Rui
  Cc: Caesar Wang, edubezval, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov, zhaoyifeng

Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > >> This add the necessary binding documentation for the thermal
> > >> found on Rockchip SoCs
> > >> 
> > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > >> ---
> > >> 
> > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > >> 
> > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > >> 
> > >>   create mode 100644
> > >> 
> > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> 
> > >> diff --git
> > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new
> > >> file
> > >> mode 100644
> > >> index 0000000..1ed4d4c
> > >> --- /dev/null
> > >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> @@ -0,0 +1,20 @@
> > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > >> +
> > >> +Required properties:
> > >> +- compatible: "rockchip,rk3288-tsadc"
> > >> +- reg: physical base address of the controller and length of memory
> > >> mapped
> > >> +       region.
> > >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> > >> format +	      depends on the interrupt controller.
> > >> +- clocks: Must contain an entry for each entry in clock-names.
> > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > >> "apb_pclk" for +	       the peripheral clock.
> > > 
> > > You're using the passive-temp, critical-temp and force-shut-temp
> > > properties in your driver without declaring them here.
> > 
> > frankly,the about are need be declared. but  there are 4 types[0] for
> > trip in thermal framework,
> > there is no force-shut for me. So I want to change it three additional
> > properties in [PATCH V4 4/4],
> > 
> > 
> > [0]
> > {
> > 
> >      THERMAL_TRIP_CRITICAL,
> >      THERMAL_TRIP_HOT,
> >      THERMAL_TRIP_PASSIVE,
> >      THERMAL_TRIP_ACTIVE,
> > 
> > }
> 
> this sounds reasonable to me.
> 
> > > But more importantly, please use the generic trip-points for this. I
> > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > trippoint [0] for the additional trip-point you have - thermal
> > > maintainers, please shout if I'm wrong :-)
> 
> what is the difference between a critical trip point and a
> "forced-shutdown" trip point?
> Thermal core will do a shutdown in case the critical trip point is
> triggered.

The forced-shutdown is where the thermal controller is supposed to also do a 
shutdown in hardware. As you said the thermal core will also shutdown at the 
critical trip point, I guess we could map Caesar's value like

trip-point		tsadc
critical		forced-shutdown (the 120 degrees in patch 4)
hot			critical (the 100 degrees)
...


> 
> thanks,
> rui
> 
> > It's a good option.
> > I can send a patch,but I don't know whether the thermal maintainers will
> > accept it.
> > 
> > Maybe,they have a better way to suggest it.:-)
> > 
> > 
> > PS:I will sent a new patch If I still have no received their suggestions
> > in two days.
> > 
> > > Heiko
> > > 
> > > 
> > > [0] in a separate patch, changing
> > > - thermal_trip_type enum in include/linux/thermal.h
> > > - trip_types mapping in drivers/thermal/of-thermal.c
> > > - Documentation/devicetree/bindings/thermal/thermal.txt
> > > 
> > >> +
> > >> +Example:
> > >> +tsadc: tsadc@ff280000 {
> > >> +	compatible = "rockchip,rk3288-tsadc";
> > >> +	reg = <0xff280000 0x100>;
> > >> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> > >> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> > >> +	clock-names = "tsadc", "apb_pclk";
> > >> +};


^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-09 11:35           ` Heiko Stübner
  0 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-09 11:35 UTC (permalink / raw)
  To: Zhang Rui
  Cc: Caesar Wang, edubezval-Re5JQEeQqe8AvxtiuMwx3w,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	huangtao-TNX95d0MmH7DzftRWevZcw, cf-TNX95d0MmH7DzftRWevZcw,
	dianders-F7+t8E8rja9g9hUCZPvPmw, dtor-F7+t8E8rja9g9hUCZPvPmw,
	zyw-TNX95d0MmH7DzftRWevZcw, addy.ke-TNX95d0MmH7DzftRWevZcw,
	dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w, zhaoyifeng

Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > >> This add the necessary binding documentation for the thermal
> > >> found on Rockchip SoCs
> > >> 
> > >> Signed-off-by: zhaoyifeng <zyf-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> > >> Signed-off-by: Caesar Wang <caesar.wang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> > >> ---
> > >> 
> > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > >> 
> > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > >> 
> > >>   create mode 100644
> > >> 
> > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> 
> > >> diff --git
> > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new
> > >> file
> > >> mode 100644
> > >> index 0000000..1ed4d4c
> > >> --- /dev/null
> > >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> @@ -0,0 +1,20 @@
> > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > >> +
> > >> +Required properties:
> > >> +- compatible: "rockchip,rk3288-tsadc"
> > >> +- reg: physical base address of the controller and length of memory
> > >> mapped
> > >> +       region.
> > >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> > >> format +	      depends on the interrupt controller.
> > >> +- clocks: Must contain an entry for each entry in clock-names.
> > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > >> "apb_pclk" for +	       the peripheral clock.
> > > 
> > > You're using the passive-temp, critical-temp and force-shut-temp
> > > properties in your driver without declaring them here.
> > 
> > frankly,the about are need be declared. but  there are 4 types[0] for
> > trip in thermal framework,
> > there is no force-shut for me. So I want to change it three additional
> > properties in [PATCH V4 4/4],
> > 
> > 
> > [0]
> > {
> > 
> >      THERMAL_TRIP_CRITICAL,
> >      THERMAL_TRIP_HOT,
> >      THERMAL_TRIP_PASSIVE,
> >      THERMAL_TRIP_ACTIVE,
> > 
> > }
> 
> this sounds reasonable to me.
> 
> > > But more importantly, please use the generic trip-points for this. I
> > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > trippoint [0] for the additional trip-point you have - thermal
> > > maintainers, please shout if I'm wrong :-)
> 
> what is the difference between a critical trip point and a
> "forced-shutdown" trip point?
> Thermal core will do a shutdown in case the critical trip point is
> triggered.

The forced-shutdown is where the thermal controller is supposed to also do a 
shutdown in hardware. As you said the thermal core will also shutdown at the 
critical trip point, I guess we could map Caesar's value like

trip-point		tsadc
critical		forced-shutdown (the 120 degrees in patch 4)
hot			critical (the 100 degrees)
...


> 
> thanks,
> rui
> 
> > It's a good option.
> > I can send a patch,but I don't know whether the thermal maintainers will
> > accept it.
> > 
> > Maybe,they have a better way to suggest it.:-)
> > 
> > 
> > PS:I will sent a new patch If I still have no received their suggestions
> > in two days.
> > 
> > > Heiko
> > > 
> > > 
> > > [0] in a separate patch, changing
> > > - thermal_trip_type enum in include/linux/thermal.h
> > > - trip_types mapping in drivers/thermal/of-thermal.c
> > > - Documentation/devicetree/bindings/thermal/thermal.txt
> > > 
> > >> +
> > >> +Example:
> > >> +tsadc: tsadc@ff280000 {
> > >> +	compatible = "rockchip,rk3288-tsadc";
> > >> +	reg = <0xff280000 0x100>;
> > >> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> > >> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> > >> +	clock-names = "tsadc", "apb_pclk";
> > >> +};

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-09 11:35           ` Heiko Stübner
  0 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-09 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > ? 2014?09?03? 16:07, Heiko St?bner ??:
> > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > >> This add the necessary binding documentation for the thermal
> > >> found on Rockchip SoCs
> > >> 
> > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > >> ---
> > >> 
> > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > >> 
> > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > >> 
> > >>   create mode 100644
> > >> 
> > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> 
> > >> diff --git
> > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new
> > >> file
> > >> mode 100644
> > >> index 0000000..1ed4d4c
> > >> --- /dev/null
> > >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> @@ -0,0 +1,20 @@
> > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > >> +
> > >> +Required properties:
> > >> +- compatible: "rockchip,rk3288-tsadc"
> > >> +- reg: physical base address of the controller and length of memory
> > >> mapped
> > >> +       region.
> > >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> > >> format +	      depends on the interrupt controller.
> > >> +- clocks: Must contain an entry for each entry in clock-names.
> > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > >> "apb_pclk" for +	       the peripheral clock.
> > > 
> > > You're using the passive-temp, critical-temp and force-shut-temp
> > > properties in your driver without declaring them here.
> > 
> > frankly,the about are need be declared. but  there are 4 types[0] for
> > trip in thermal framework,
> > there is no force-shut for me. So I want to change it three additional
> > properties in [PATCH V4 4/4],
> > 
> > 
> > [0]
> > {
> > 
> >      THERMAL_TRIP_CRITICAL,
> >      THERMAL_TRIP_HOT,
> >      THERMAL_TRIP_PASSIVE,
> >      THERMAL_TRIP_ACTIVE,
> > 
> > }
> 
> this sounds reasonable to me.
> 
> > > But more importantly, please use the generic trip-points for this. I
> > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > trippoint [0] for the additional trip-point you have - thermal
> > > maintainers, please shout if I'm wrong :-)
> 
> what is the difference between a critical trip point and a
> "forced-shutdown" trip point?
> Thermal core will do a shutdown in case the critical trip point is
> triggered.

The forced-shutdown is where the thermal controller is supposed to also do a 
shutdown in hardware. As you said the thermal core will also shutdown at the 
critical trip point, I guess we could map Caesar's value like

trip-point		tsadc
critical		forced-shutdown (the 120 degrees in patch 4)
hot			critical (the 100 degrees)
...


> 
> thanks,
> rui
> 
> > It's a good option.
> > I can send a patch,but I don't know whether the thermal maintainers will
> > accept it.
> > 
> > Maybe,they have a better way to suggest it.:-)
> > 
> > 
> > PS:I will sent a new patch If I still have no received their suggestions
> > in two days.
> > 
> > > Heiko
> > > 
> > > 
> > > [0] in a separate patch, changing
> > > - thermal_trip_type enum in include/linux/thermal.h
> > > - trip_types mapping in drivers/thermal/of-thermal.c
> > > - Documentation/devicetree/bindings/thermal/thermal.txt
> > > 
> > >> +
> > >> +Example:
> > >> +tsadc: tsadc at ff280000 {
> > >> +	compatible = "rockchip,rk3288-tsadc";
> > >> +	reg = <0xff280000 0x100>;
> > >> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> > >> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> > >> +	clock-names = "tsadc", "apb_pclk";
> > >> +};

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 3/4] ARM: dts: add main Thermal info to rk3288
  2014-09-03  2:10   ` Caesar Wang
@ 2014-09-09 11:37     ` Heiko Stübner
  -1 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-09 11:37 UTC (permalink / raw)
  To: Caesar Wang
  Cc: rui.zhang, edubezval, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov

Am Mittwoch, 3. September 2014, 10:10:38 schrieb Caesar Wang:
> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> ---
>  arch/arm/boot/dts/rk3288.dtsi | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
> index 36be7bb..3d672e3 100644
> --- a/arch/arm/boot/dts/rk3288.dtsi
> +++ b/arch/arm/boot/dts/rk3288.dtsi
> @@ -224,6 +224,17 @@
>  		status = "disabled";
>  	};
> 
> +	tsadc: tsadc@ff280000 {

please keep the list of nodes sorted by register address. So when looking at 
my v3.18-next/dts branch, it should be after uart4: serial@ff1c0000 and before 
usb_host0_ehci: usb@ff500000 .


> +		compatible = "rockchip,rk3288-tsadc";
> +		reg = <0xff280000 0x100>;
> +		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> +		clock-names = "tsadc", "apb_pclk";
> +		pinctrl-names = "default";
> +		pinctrl-1 = <&tsadc_int>;
> +		status = "disabled";
> +	};
> +
>  	/* NOTE: ohci@ff520000 doesn't actually work on hardware */
> 
>  	usb_hsic: usb@ff5c0000 {
> @@ -611,5 +622,12 @@
>  				rockchip,pins = <5 15 3 &pcfg_pull_none>;
>  			};
>  		};
> +
> +		tsadc {
> +			tsadc_int: tsadc-int {
> +				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
> +			};
> +		};

After looking this up in the schematics I see that this is the 
overtemperature-protection output pin ... labeled OTP_OUT.
So I'd think the pinconfig should reflect this pin-name, especially as tsadc-int 
suggests, that this would be an interrupt leading into the tsadc, while in 
fact it is an output to a separate circuit.


Heiko

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 3/4] ARM: dts: add main Thermal info to rk3288
@ 2014-09-09 11:37     ` Heiko Stübner
  0 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-09 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

Am Mittwoch, 3. September 2014, 10:10:38 schrieb Caesar Wang:
> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> ---
>  arch/arm/boot/dts/rk3288.dtsi | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
> index 36be7bb..3d672e3 100644
> --- a/arch/arm/boot/dts/rk3288.dtsi
> +++ b/arch/arm/boot/dts/rk3288.dtsi
> @@ -224,6 +224,17 @@
>  		status = "disabled";
>  	};
> 
> +	tsadc: tsadc at ff280000 {

please keep the list of nodes sorted by register address. So when looking at 
my v3.18-next/dts branch, it should be after uart4: serial at ff1c0000 and before 
usb_host0_ehci: usb at ff500000 .


> +		compatible = "rockchip,rk3288-tsadc";
> +		reg = <0xff280000 0x100>;
> +		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> +		clock-names = "tsadc", "apb_pclk";
> +		pinctrl-names = "default";
> +		pinctrl-1 = <&tsadc_int>;
> +		status = "disabled";
> +	};
> +
>  	/* NOTE: ohci at ff520000 doesn't actually work on hardware */
> 
>  	usb_hsic: usb at ff5c0000 {
> @@ -611,5 +622,12 @@
>  				rockchip,pins = <5 15 3 &pcfg_pull_none>;
>  			};
>  		};
> +
> +		tsadc {
> +			tsadc_int: tsadc-int {
> +				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
> +			};
> +		};

After looking this up in the schematics I see that this is the 
overtemperature-protection output pin ... labeled OTP_OUT.
So I'd think the pinconfig should reflect this pin-name, especially as tsadc-int 
suggests, that this would be an interrupt leading into the tsadc, while in 
fact it is an output to a separate circuit.


Heiko

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-09 11:35           ` Heiko Stübner
  (?)
@ 2014-09-09 15:09             ` Eduardo Valentin
  -1 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-09-09 15:09 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Zhang Rui, Caesar Wang, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov, zhaoyifeng

Hello

On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko Stübner wrote:
> Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > > >> This add the necessary binding documentation for the thermal
> > > >> found on Rockchip SoCs
> > > >> 
> > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > > >> ---
> > > >> 
> > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > > >> 
> > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > > >> 
> > > >>   create mode 100644
> > > >> 
> > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> 
> > > >> diff --git
> > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new
> > > >> file
> > > >> mode 100644
> > > >> index 0000000..1ed4d4c
> > > >> --- /dev/null
> > > >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> @@ -0,0 +1,20 @@
> > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > > >> +
> > > >> +Required properties:
> > > >> +- compatible: "rockchip,rk3288-tsadc"
> > > >> +- reg: physical base address of the controller and length of memory
> > > >> mapped
> > > >> +       region.
> > > >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> > > >> format +	      depends on the interrupt controller.
> > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > > >> "apb_pclk" for +	       the peripheral clock.
> > > > 
> > > > You're using the passive-temp, critical-temp and force-shut-temp
> > > > properties in your driver without declaring them here.
> > > 
> > > frankly,the about are need be declared. but  there are 4 types[0] for
> > > trip in thermal framework,
> > > there is no force-shut for me. So I want to change it three additional
> > > properties in [PATCH V4 4/4],
> > > 
> > > 
> > > [0]
> > > {
> > > 
> > >      THERMAL_TRIP_CRITICAL,
> > >      THERMAL_TRIP_HOT,
> > >      THERMAL_TRIP_PASSIVE,
> > >      THERMAL_TRIP_ACTIVE,
> > > 
> > > }
> > 
> > this sounds reasonable to me.
> > 
> > > > But more importantly, please use the generic trip-points for this. I
> > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > > trippoint [0] for the additional trip-point you have - thermal
> > > > maintainers, please shout if I'm wrong :-)
> > 
> > what is the difference between a critical trip point and a
> > "forced-shutdown" trip point?
> > Thermal core will do a shutdown in case the critical trip point is
> > triggered.
> 
> The forced-shutdown is where the thermal controller is supposed to also do a 

Currently, there is no discrimination between hardware configured /
triggered thermal shutdown and software detected / triggered thermal shutdown.
One way to implement it though is to reuse the critical trip type. Even
if you use more than one trip type it is doable, it will depend on the
priorities you give to software triggered and hardware triggered.

> shutdown in hardware. As you said the thermal core will also shutdown at the 
> critical trip point, I guess we could map Caesar's value like
> 
> trip-point		tsadc
> critical		forced-shutdown (the 120 degrees in patch 4)

> hot			critical (the 100 degrees)
> ...
> 
> 

In the case we are planing to expand the trip type range, adding one
specific to hardware configurable shutdown makes sense to me too.
Alhtough, as I mention, I believe with the current generic trip types,
this situation can be covered already. Besides, I believe
'forced-shutdown' does not sound a descriptive enough though. I would
suggest something more specific, say 'hardware-shutdown'. 

> > 
> > thanks,
> > rui
> > 
> > > It's a good option.
> > > I can send a patch,but I don't know whether the thermal maintainers will
> > > accept it.
> > > 
> > > Maybe,they have a better way to suggest it.:-)
> > > 
> > > 
> > > PS:I will sent a new patch If I still have no received their suggestions
> > > in two days.
> > > 
> > > > Heiko
> > > > 
> > > > 
> > > > [0] in a separate patch, changing
> > > > - thermal_trip_type enum in include/linux/thermal.h
> > > > - trip_types mapping in drivers/thermal/of-thermal.c
> > > > - Documentation/devicetree/bindings/thermal/thermal.txt
> > > > 
> > > >> +
> > > >> +Example:
> > > >> +tsadc: tsadc@ff280000 {
> > > >> +	compatible = "rockchip,rk3288-tsadc";
> > > >> +	reg = <0xff280000 0x100>;
> > > >> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> > > >> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> > > >> +	clock-names = "tsadc", "apb_pclk";
> > > >> +};
> 


^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-09 15:09             ` Eduardo Valentin
  0 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-09-09 15:09 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Zhang Rui, Caesar Wang, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	huangtao-TNX95d0MmH7DzftRWevZcw, cf-TNX95d0MmH7DzftRWevZcw,
	dianders-F7+t8E8rja9g9hUCZPvPmw, dtor-F7+t8E8rja9g9hUCZPvPmw,
	zyw-TNX95d0MmH7DzftRWevZcw, addy.ke-TNX95d0MmH7DzftRWevZcw,
	dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w, zhaoyifeng

Hello

On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko Stübner wrote:
> Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > > >> This add the necessary binding documentation for the thermal
> > > >> found on Rockchip SoCs
> > > >> 
> > > >> Signed-off-by: zhaoyifeng <zyf-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> > > >> Signed-off-by: Caesar Wang <caesar.wang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> > > >> ---
> > > >> 
> > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > > >> 
> > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > > >> 
> > > >>   create mode 100644
> > > >> 
> > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> 
> > > >> diff --git
> > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new
> > > >> file
> > > >> mode 100644
> > > >> index 0000000..1ed4d4c
> > > >> --- /dev/null
> > > >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> @@ -0,0 +1,20 @@
> > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > > >> +
> > > >> +Required properties:
> > > >> +- compatible: "rockchip,rk3288-tsadc"
> > > >> +- reg: physical base address of the controller and length of memory
> > > >> mapped
> > > >> +       region.
> > > >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> > > >> format +	      depends on the interrupt controller.
> > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > > >> "apb_pclk" for +	       the peripheral clock.
> > > > 
> > > > You're using the passive-temp, critical-temp and force-shut-temp
> > > > properties in your driver without declaring them here.
> > > 
> > > frankly,the about are need be declared. but  there are 4 types[0] for
> > > trip in thermal framework,
> > > there is no force-shut for me. So I want to change it three additional
> > > properties in [PATCH V4 4/4],
> > > 
> > > 
> > > [0]
> > > {
> > > 
> > >      THERMAL_TRIP_CRITICAL,
> > >      THERMAL_TRIP_HOT,
> > >      THERMAL_TRIP_PASSIVE,
> > >      THERMAL_TRIP_ACTIVE,
> > > 
> > > }
> > 
> > this sounds reasonable to me.
> > 
> > > > But more importantly, please use the generic trip-points for this. I
> > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > > trippoint [0] for the additional trip-point you have - thermal
> > > > maintainers, please shout if I'm wrong :-)
> > 
> > what is the difference between a critical trip point and a
> > "forced-shutdown" trip point?
> > Thermal core will do a shutdown in case the critical trip point is
> > triggered.
> 
> The forced-shutdown is where the thermal controller is supposed to also do a 

Currently, there is no discrimination between hardware configured /
triggered thermal shutdown and software detected / triggered thermal shutdown.
One way to implement it though is to reuse the critical trip type. Even
if you use more than one trip type it is doable, it will depend on the
priorities you give to software triggered and hardware triggered.

> shutdown in hardware. As you said the thermal core will also shutdown at the 
> critical trip point, I guess we could map Caesar's value like
> 
> trip-point		tsadc
> critical		forced-shutdown (the 120 degrees in patch 4)

> hot			critical (the 100 degrees)
> ...
> 
> 

In the case we are planing to expand the trip type range, adding one
specific to hardware configurable shutdown makes sense to me too.
Alhtough, as I mention, I believe with the current generic trip types,
this situation can be covered already. Besides, I believe
'forced-shutdown' does not sound a descriptive enough though. I would
suggest something more specific, say 'hardware-shutdown'. 

> > 
> > thanks,
> > rui
> > 
> > > It's a good option.
> > > I can send a patch,but I don't know whether the thermal maintainers will
> > > accept it.
> > > 
> > > Maybe,they have a better way to suggest it.:-)
> > > 
> > > 
> > > PS:I will sent a new patch If I still have no received their suggestions
> > > in two days.
> > > 
> > > > Heiko
> > > > 
> > > > 
> > > > [0] in a separate patch, changing
> > > > - thermal_trip_type enum in include/linux/thermal.h
> > > > - trip_types mapping in drivers/thermal/of-thermal.c
> > > > - Documentation/devicetree/bindings/thermal/thermal.txt
> > > > 
> > > >> +
> > > >> +Example:
> > > >> +tsadc: tsadc@ff280000 {
> > > >> +	compatible = "rockchip,rk3288-tsadc";
> > > >> +	reg = <0xff280000 0x100>;
> > > >> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> > > >> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> > > >> +	clock-names = "tsadc", "apb_pclk";
> > > >> +};
> 

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-09 15:09             ` Eduardo Valentin
  0 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-09-09 15:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hello

On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko St?bner wrote:
> Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > > ? 2014?09?03? 16:07, Heiko St?bner ??:
> > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > > >> This add the necessary binding documentation for the thermal
> > > >> found on Rockchip SoCs
> > > >> 
> > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > > >> ---
> > > >> 
> > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > > >> 
> > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > > >> 
> > > >>   create mode 100644
> > > >> 
> > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> 
> > > >> diff --git
> > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new
> > > >> file
> > > >> mode 100644
> > > >> index 0000000..1ed4d4c
> > > >> --- /dev/null
> > > >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> @@ -0,0 +1,20 @@
> > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > > >> +
> > > >> +Required properties:
> > > >> +- compatible: "rockchip,rk3288-tsadc"
> > > >> +- reg: physical base address of the controller and length of memory
> > > >> mapped
> > > >> +       region.
> > > >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> > > >> format +	      depends on the interrupt controller.
> > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > > >> "apb_pclk" for +	       the peripheral clock.
> > > > 
> > > > You're using the passive-temp, critical-temp and force-shut-temp
> > > > properties in your driver without declaring them here.
> > > 
> > > frankly,the about are need be declared. but  there are 4 types[0] for
> > > trip in thermal framework,
> > > there is no force-shut for me. So I want to change it three additional
> > > properties in [PATCH V4 4/4],
> > > 
> > > 
> > > [0]
> > > {
> > > 
> > >      THERMAL_TRIP_CRITICAL,
> > >      THERMAL_TRIP_HOT,
> > >      THERMAL_TRIP_PASSIVE,
> > >      THERMAL_TRIP_ACTIVE,
> > > 
> > > }
> > 
> > this sounds reasonable to me.
> > 
> > > > But more importantly, please use the generic trip-points for this. I
> > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > > trippoint [0] for the additional trip-point you have - thermal
> > > > maintainers, please shout if I'm wrong :-)
> > 
> > what is the difference between a critical trip point and a
> > "forced-shutdown" trip point?
> > Thermal core will do a shutdown in case the critical trip point is
> > triggered.
> 
> The forced-shutdown is where the thermal controller is supposed to also do a 

Currently, there is no discrimination between hardware configured /
triggered thermal shutdown and software detected / triggered thermal shutdown.
One way to implement it though is to reuse the critical trip type. Even
if you use more than one trip type it is doable, it will depend on the
priorities you give to software triggered and hardware triggered.

> shutdown in hardware. As you said the thermal core will also shutdown at the 
> critical trip point, I guess we could map Caesar's value like
> 
> trip-point		tsadc
> critical		forced-shutdown (the 120 degrees in patch 4)

> hot			critical (the 100 degrees)
> ...
> 
> 

In the case we are planing to expand the trip type range, adding one
specific to hardware configurable shutdown makes sense to me too.
Alhtough, as I mention, I believe with the current generic trip types,
this situation can be covered already. Besides, I believe
'forced-shutdown' does not sound a descriptive enough though. I would
suggest something more specific, say 'hardware-shutdown'. 

> > 
> > thanks,
> > rui
> > 
> > > It's a good option.
> > > I can send a patch,but I don't know whether the thermal maintainers will
> > > accept it.
> > > 
> > > Maybe,they have a better way to suggest it.:-)
> > > 
> > > 
> > > PS:I will sent a new patch If I still have no received their suggestions
> > > in two days.
> > > 
> > > > Heiko
> > > > 
> > > > 
> > > > [0] in a separate patch, changing
> > > > - thermal_trip_type enum in include/linux/thermal.h
> > > > - trip_types mapping in drivers/thermal/of-thermal.c
> > > > - Documentation/devicetree/bindings/thermal/thermal.txt
> > > > 
> > > >> +
> > > >> +Example:
> > > >> +tsadc: tsadc at ff280000 {
> > > >> +	compatible = "rockchip,rk3288-tsadc";
> > > >> +	reg = <0xff280000 0x100>;
> > > >> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> > > >> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> > > >> +	clock-names = "tsadc", "apb_pclk";
> > > >> +};
> 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-09 15:09             ` Eduardo Valentin
@ 2014-09-10  1:02               ` Zhang Rui
  -1 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-10  1:02 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: Heiko Stübner, Caesar Wang, linux-kernel, linux-pm,
	linux-arm-kernel, devicetree, linux-doc, huangtao, cf, dianders,
	dtor, zyw, addy.ke, dmitry.torokhov, zhaoyifeng

On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> Hello
> 
> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko Stübner wrote:
> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > > > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > > > >> This add the necessary binding documentation for the thermal
> > > > >> found on Rockchip SoCs
> > > > >> 
> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > > > >> ---
> > > > >> 
> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > > > >> 
> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > > > >> 
> > > > >>   create mode 100644
> > > > >> 
> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > > >> 
> > > > >> diff --git
> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new
> > > > >> file
> > > > >> mode 100644
> > > > >> index 0000000..1ed4d4c
> > > > >> --- /dev/null
> > > > >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > > >> @@ -0,0 +1,20 @@
> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > > > >> +
> > > > >> +Required properties:
> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> > > > >> +- reg: physical base address of the controller and length of memory
> > > > >> mapped
> > > > >> +       region.
> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> > > > >> format +	      depends on the interrupt controller.
> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > > > >> "apb_pclk" for +	       the peripheral clock.
> > > > > 
> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> > > > > properties in your driver without declaring them here.
> > > > 
> > > > frankly,the about are need be declared. but  there are 4 types[0] for
> > > > trip in thermal framework,
> > > > there is no force-shut for me. So I want to change it three additional
> > > > properties in [PATCH V4 4/4],
> > > > 
> > > > 
> > > > [0]
> > > > {
> > > > 
> > > >      THERMAL_TRIP_CRITICAL,
> > > >      THERMAL_TRIP_HOT,
> > > >      THERMAL_TRIP_PASSIVE,
> > > >      THERMAL_TRIP_ACTIVE,
> > > > 
> > > > }
> > > 
> > > this sounds reasonable to me.
> > > 
> > > > > But more importantly, please use the generic trip-points for this. I
> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > > > trippoint [0] for the additional trip-point you have - thermal
> > > > > maintainers, please shout if I'm wrong :-)
> > > 
> > > what is the difference between a critical trip point and a
> > > "forced-shutdown" trip point?
> > > Thermal core will do a shutdown in case the critical trip point is
> > > triggered.
> > 
> > The forced-shutdown is where the thermal controller is supposed to also do a 
> 
> Currently, there is no discrimination between hardware configured /
> triggered thermal shutdown and software detected / triggered thermal shutdown.
> One way to implement it though is to reuse the critical trip type. Even
> if you use more than one trip type it is doable, it will depend on the
> priorities you give to software triggered and hardware triggered.
> 
> > shutdown in hardware. As you said the thermal core will also shutdown at the 
> > critical trip point, I guess we could map Caesar's value like
> > 
> > trip-point		tsadc
> > critical		forced-shutdown (the 120 degrees in patch 4)
> 
> > hot			critical (the 100 degrees)
> > ...
> > 
> > 
> 
> In the case we are planing to expand the trip type range, adding one
> specific to hardware configurable shutdown makes sense to me too.
hmmm, why? you don't want an orderly shutdown? I still do not understand
why we need a hardware shutdown trip point.
Say, if we expect the system to be shutdown at 100C, I don't think we
have a chance to trigger the hardware shutdown trip point.
Further more, if my understanding is right, thermal core won't do
anything for the hardware shutdown trip point because the system will be
shutdown automatically, right? If this is true, why bother introducing
this to thermal core?

thanks,
rui
> Alhtough, as I mention, I believe with the current generic trip types,
> this situation can be covered already.
>  Besides, I believe
> 'forced-shutdown' does not sound a descriptive enough though. I would
> suggest something more specific, say 'hardware-shutdown'. 
> 
> > > 
> > > thanks,
> > > rui
> > > 
> > > > It's a good option.
> > > > I can send a patch,but I don't know whether the thermal maintainers will
> > > > accept it.
> > > > 
> > > > Maybe,they have a better way to suggest it.:-)
> > > > 
> > > > 
> > > > PS:I will sent a new patch If I still have no received their suggestions
> > > > in two days.
> > > > 
> > > > > Heiko
> > > > > 
> > > > > 
> > > > > [0] in a separate patch, changing
> > > > > - thermal_trip_type enum in include/linux/thermal.h
> > > > > - trip_types mapping in drivers/thermal/of-thermal.c
> > > > > - Documentation/devicetree/bindings/thermal/thermal.txt
> > > > > 
> > > > >> +
> > > > >> +Example:
> > > > >> +tsadc: tsadc@ff280000 {
> > > > >> +	compatible = "rockchip,rk3288-tsadc";
> > > > >> +	reg = <0xff280000 0x100>;
> > > > >> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> > > > >> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> > > > >> +	clock-names = "tsadc", "apb_pclk";
> > > > >> +};
> > 
> 



^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-10  1:02               ` Zhang Rui
  0 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-10  1:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> Hello
> 
> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko St?bner wrote:
> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > > > ? 2014?09?03? 16:07, Heiko St?bner ??:
> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > > > >> This add the necessary binding documentation for the thermal
> > > > >> found on Rockchip SoCs
> > > > >> 
> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > > > >> ---
> > > > >> 
> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > > > >> 
> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > > > >> 
> > > > >>   create mode 100644
> > > > >> 
> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > > >> 
> > > > >> diff --git
> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new
> > > > >> file
> > > > >> mode 100644
> > > > >> index 0000000..1ed4d4c
> > > > >> --- /dev/null
> > > > >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > > >> @@ -0,0 +1,20 @@
> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > > > >> +
> > > > >> +Required properties:
> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> > > > >> +- reg: physical base address of the controller and length of memory
> > > > >> mapped
> > > > >> +       region.
> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
> > > > >> format +	      depends on the interrupt controller.
> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > > > >> "apb_pclk" for +	       the peripheral clock.
> > > > > 
> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> > > > > properties in your driver without declaring them here.
> > > > 
> > > > frankly,the about are need be declared. but  there are 4 types[0] for
> > > > trip in thermal framework,
> > > > there is no force-shut for me. So I want to change it three additional
> > > > properties in [PATCH V4 4/4],
> > > > 
> > > > 
> > > > [0]
> > > > {
> > > > 
> > > >      THERMAL_TRIP_CRITICAL,
> > > >      THERMAL_TRIP_HOT,
> > > >      THERMAL_TRIP_PASSIVE,
> > > >      THERMAL_TRIP_ACTIVE,
> > > > 
> > > > }
> > > 
> > > this sounds reasonable to me.
> > > 
> > > > > But more importantly, please use the generic trip-points for this. I
> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > > > trippoint [0] for the additional trip-point you have - thermal
> > > > > maintainers, please shout if I'm wrong :-)
> > > 
> > > what is the difference between a critical trip point and a
> > > "forced-shutdown" trip point?
> > > Thermal core will do a shutdown in case the critical trip point is
> > > triggered.
> > 
> > The forced-shutdown is where the thermal controller is supposed to also do a 
> 
> Currently, there is no discrimination between hardware configured /
> triggered thermal shutdown and software detected / triggered thermal shutdown.
> One way to implement it though is to reuse the critical trip type. Even
> if you use more than one trip type it is doable, it will depend on the
> priorities you give to software triggered and hardware triggered.
> 
> > shutdown in hardware. As you said the thermal core will also shutdown at the 
> > critical trip point, I guess we could map Caesar's value like
> > 
> > trip-point		tsadc
> > critical		forced-shutdown (the 120 degrees in patch 4)
> 
> > hot			critical (the 100 degrees)
> > ...
> > 
> > 
> 
> In the case we are planing to expand the trip type range, adding one
> specific to hardware configurable shutdown makes sense to me too.
hmmm, why? you don't want an orderly shutdown? I still do not understand
why we need a hardware shutdown trip point.
Say, if we expect the system to be shutdown at 100C, I don't think we
have a chance to trigger the hardware shutdown trip point.
Further more, if my understanding is right, thermal core won't do
anything for the hardware shutdown trip point because the system will be
shutdown automatically, right? If this is true, why bother introducing
this to thermal core?

thanks,
rui
> Alhtough, as I mention, I believe with the current generic trip types,
> this situation can be covered already.
>  Besides, I believe
> 'forced-shutdown' does not sound a descriptive enough though. I would
> suggest something more specific, say 'hardware-shutdown'. 
> 
> > > 
> > > thanks,
> > > rui
> > > 
> > > > It's a good option.
> > > > I can send a patch,but I don't know whether the thermal maintainers will
> > > > accept it.
> > > > 
> > > > Maybe,they have a better way to suggest it.:-)
> > > > 
> > > > 
> > > > PS:I will sent a new patch If I still have no received their suggestions
> > > > in two days.
> > > > 
> > > > > Heiko
> > > > > 
> > > > > 
> > > > > [0] in a separate patch, changing
> > > > > - thermal_trip_type enum in include/linux/thermal.h
> > > > > - trip_types mapping in drivers/thermal/of-thermal.c
> > > > > - Documentation/devicetree/bindings/thermal/thermal.txt
> > > > > 
> > > > >> +
> > > > >> +Example:
> > > > >> +tsadc: tsadc at ff280000 {
> > > > >> +	compatible = "rockchip,rk3288-tsadc";
> > > > >> +	reg = <0xff280000 0x100>;
> > > > >> +	interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> > > > >> +	clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
> > > > >> +	clock-names = "tsadc", "apb_pclk";
> > > > >> +};
> > 
> 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-10  1:02               ` Zhang Rui
@ 2014-09-10  1:14                 ` edubezval at gmail.com
  -1 siblings, 0 replies; 65+ messages in thread
From: edubezval @ 2014-09-10  1:14 UTC (permalink / raw)
  To: Zhang Rui
  Cc: Heiko Stübner, Caesar Wang, LKML, linux-pm,
	linux-arm-kernel, devicetree, linux-doc, Tao Huang, Eddie Cai,
	Douglas Anderson, dtor, Chris Zhong, addy.ke, Dmitry Torokhov,
	zhaoyifeng

Hello,

On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang@intel.com> wrote:
> On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
>> Hello
>>
>> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko Stübner wrote:
>> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
>> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
>> > > > 在 2014年09月03日 16:07, Heiko Stübner 写道:
>> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
>> > > > >> This add the necessary binding documentation for the thermal
>> > > > >> found on Rockchip SoCs
>> > > > >>
>> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
>> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>> > > > >> ---
>> > > > >>
>> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
>> > > > >>
>> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
>> > > > >>
>> > > > >>   create mode 100644
>> > > > >>
>> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>> > > > >>
>> > > > >> diff --git
>> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new
>> > > > >> file
>> > > > >> mode 100644
>> > > > >> index 0000000..1ed4d4c
>> > > > >> --- /dev/null
>> > > > >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>> > > > >> @@ -0,0 +1,20 @@
>> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
>> > > > >> +
>> > > > >> +Required properties:
>> > > > >> +- compatible: "rockchip,rk3288-tsadc"
>> > > > >> +- reg: physical base address of the controller and length of memory
>> > > > >> mapped
>> > > > >> +       region.
>> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
>> > > > >> format +           depends on the interrupt controller.
>> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
>> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
>> > > > >> "apb_pclk" for +            the peripheral clock.
>> > > > >
>> > > > > You're using the passive-temp, critical-temp and force-shut-temp
>> > > > > properties in your driver without declaring them here.
>> > > >
>> > > > frankly,the about are need be declared. but  there are 4 types[0] for
>> > > > trip in thermal framework,
>> > > > there is no force-shut for me. So I want to change it three additional
>> > > > properties in [PATCH V4 4/4],
>> > > >
>> > > >
>> > > > [0]
>> > > > {
>> > > >
>> > > >      THERMAL_TRIP_CRITICAL,
>> > > >      THERMAL_TRIP_HOT,
>> > > >      THERMAL_TRIP_PASSIVE,
>> > > >      THERMAL_TRIP_ACTIVE,
>> > > >
>> > > > }
>> > >
>> > > this sounds reasonable to me.
>> > >
>> > > > > But more importantly, please use the generic trip-points for this. I
>> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
>> > > > > trippoint [0] for the additional trip-point you have - thermal
>> > > > > maintainers, please shout if I'm wrong :-)
>> > >
>> > > what is the difference between a critical trip point and a
>> > > "forced-shutdown" trip point?
>> > > Thermal core will do a shutdown in case the critical trip point is
>> > > triggered.
>> >
>> > The forced-shutdown is where the thermal controller is supposed to also do a
>>
>> Currently, there is no discrimination between hardware configured /
>> triggered thermal shutdown and software detected / triggered thermal shutdown.
>> One way to implement it though is to reuse the critical trip type. Even
>> if you use more than one trip type it is doable, it will depend on the
>> priorities you give to software triggered and hardware triggered.
>>
>> > shutdown in hardware. As you said the thermal core will also shutdown at the
>> > critical trip point, I guess we could map Caesar's value like
>> >
>> > trip-point          tsadc
>> > critical            forced-shutdown (the 120 degrees in patch 4)
>>
>> > hot                 critical (the 100 degrees)
>> > ...
>> >
>> >
>>
>> In the case we are planing to expand the trip type range, adding one
>> specific to hardware configurable shutdown makes sense to me too.
> hmmm, why? you don't want an orderly shutdown? I still do not understand
> why we need a hardware shutdown trip point.
> Say, if we expect the system to be shutdown at 100C, I don't think we
> have a chance to trigger the hardware shutdown trip point.
> Further more, if my understanding is right, thermal core won't do
> anything for the hardware shutdown trip point because the system will be
> shutdown automatically, right? If this is true, why bother introducing
> this to thermal core?
>

Some ICs allow configuring the temperature when the shutdown will
happen. That is, you setup in registers the thermal shutdown
threshold, and one of the output pin of the IC is wired to, say, the
processor reset pin. Some other ICs have the threshold hardwired, and
cannot be configured.

Those options are a last chance to avoid processors to burn, in case
software really gets stuck at high temperatures.

The only thing that the thermal driver would need to worry is the
configuration step, that is, writing the value to the registers. In
the case the thermal core would have a specific trip type for such
case, the core itself would not do anything, except allowing designing
a thermal zone with hardware shutdown trips. And thus the thermal
driver would do the configuration.


Currently, the way I see to implement this is to interpret critical
trips as the threshold to be configured at the IC registers. That is,
reusing critical trips as orderly power down and as the hardware
shutdown threshold.

> thanks,
> rui
>> Alhtough, as I mention, I believe with the current generic trip types,
>> this situation can be covered already.
>>  Besides, I believe
>> 'forced-shutdown' does not sound a descriptive enough though. I would
>> suggest something more specific, say 'hardware-shutdown'.
>>
>> > >
>> > > thanks,
>> > > rui
>> > >
>> > > > It's a good option.
>> > > > I can send a patch,but I don't know whether the thermal maintainers will
>> > > > accept it.
>> > > >
>> > > > Maybe,they have a better way to suggest it.:-)
>> > > >
>> > > >
>> > > > PS:I will sent a new patch If I still have no received their suggestions
>> > > > in two days.
>> > > >
>> > > > > Heiko
>> > > > >
>> > > > >
>> > > > > [0] in a separate patch, changing
>> > > > > - thermal_trip_type enum in include/linux/thermal.h
>> > > > > - trip_types mapping in drivers/thermal/of-thermal.c
>> > > > > - Documentation/devicetree/bindings/thermal/thermal.txt
>> > > > >
>> > > > >> +
>> > > > >> +Example:
>> > > > >> +tsadc: tsadc@ff280000 {
>> > > > >> +    compatible = "rockchip,rk3288-tsadc";
>> > > > >> +    reg = <0xff280000 0x100>;
>> > > > >> +    interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
>> > > > >> +    clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
>> > > > >> +    clock-names = "tsadc", "apb_pclk";
>> > > > >> +};
>> >
>>
>
>



-- 
Eduardo Bezerra Valentin

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-10  1:14                 ` edubezval at gmail.com
  0 siblings, 0 replies; 65+ messages in thread
From: edubezval at gmail.com @ 2014-09-10  1:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang@intel.com> wrote:
> On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
>> Hello
>>
>> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko St?bner wrote:
>> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
>> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
>> > > > ? 2014?09?03? 16:07, Heiko St?bner ??:
>> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
>> > > > >> This add the necessary binding documentation for the thermal
>> > > > >> found on Rockchip SoCs
>> > > > >>
>> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
>> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>> > > > >> ---
>> > > > >>
>> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
>> > > > >>
>> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
>> > > > >>
>> > > > >>   create mode 100644
>> > > > >>
>> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>> > > > >>
>> > > > >> diff --git
>> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt new
>> > > > >> file
>> > > > >> mode 100644
>> > > > >> index 0000000..1ed4d4c
>> > > > >> --- /dev/null
>> > > > >> +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
>> > > > >> @@ -0,0 +1,20 @@
>> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
>> > > > >> +
>> > > > >> +Required properties:
>> > > > >> +- compatible: "rockchip,rk3288-tsadc"
>> > > > >> +- reg: physical base address of the controller and length of memory
>> > > > >> mapped
>> > > > >> +       region.
>> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt specifier
>> > > > >> format +           depends on the interrupt controller.
>> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
>> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
>> > > > >> "apb_pclk" for +            the peripheral clock.
>> > > > >
>> > > > > You're using the passive-temp, critical-temp and force-shut-temp
>> > > > > properties in your driver without declaring them here.
>> > > >
>> > > > frankly,the about are need be declared. but  there are 4 types[0] for
>> > > > trip in thermal framework,
>> > > > there is no force-shut for me. So I want to change it three additional
>> > > > properties in [PATCH V4 4/4],
>> > > >
>> > > >
>> > > > [0]
>> > > > {
>> > > >
>> > > >      THERMAL_TRIP_CRITICAL,
>> > > >      THERMAL_TRIP_HOT,
>> > > >      THERMAL_TRIP_PASSIVE,
>> > > >      THERMAL_TRIP_ACTIVE,
>> > > >
>> > > > }
>> > >
>> > > this sounds reasonable to me.
>> > >
>> > > > > But more importantly, please use the generic trip-points for this. I
>> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
>> > > > > trippoint [0] for the additional trip-point you have - thermal
>> > > > > maintainers, please shout if I'm wrong :-)
>> > >
>> > > what is the difference between a critical trip point and a
>> > > "forced-shutdown" trip point?
>> > > Thermal core will do a shutdown in case the critical trip point is
>> > > triggered.
>> >
>> > The forced-shutdown is where the thermal controller is supposed to also do a
>>
>> Currently, there is no discrimination between hardware configured /
>> triggered thermal shutdown and software detected / triggered thermal shutdown.
>> One way to implement it though is to reuse the critical trip type. Even
>> if you use more than one trip type it is doable, it will depend on the
>> priorities you give to software triggered and hardware triggered.
>>
>> > shutdown in hardware. As you said the thermal core will also shutdown at the
>> > critical trip point, I guess we could map Caesar's value like
>> >
>> > trip-point          tsadc
>> > critical            forced-shutdown (the 120 degrees in patch 4)
>>
>> > hot                 critical (the 100 degrees)
>> > ...
>> >
>> >
>>
>> In the case we are planing to expand the trip type range, adding one
>> specific to hardware configurable shutdown makes sense to me too.
> hmmm, why? you don't want an orderly shutdown? I still do not understand
> why we need a hardware shutdown trip point.
> Say, if we expect the system to be shutdown at 100C, I don't think we
> have a chance to trigger the hardware shutdown trip point.
> Further more, if my understanding is right, thermal core won't do
> anything for the hardware shutdown trip point because the system will be
> shutdown automatically, right? If this is true, why bother introducing
> this to thermal core?
>

Some ICs allow configuring the temperature when the shutdown will
happen. That is, you setup in registers the thermal shutdown
threshold, and one of the output pin of the IC is wired to, say, the
processor reset pin. Some other ICs have the threshold hardwired, and
cannot be configured.

Those options are a last chance to avoid processors to burn, in case
software really gets stuck at high temperatures.

The only thing that the thermal driver would need to worry is the
configuration step, that is, writing the value to the registers. In
the case the thermal core would have a specific trip type for such
case, the core itself would not do anything, except allowing designing
a thermal zone with hardware shutdown trips. And thus the thermal
driver would do the configuration.


Currently, the way I see to implement this is to interpret critical
trips as the threshold to be configured at the IC registers. That is,
reusing critical trips as orderly power down and as the hardware
shutdown threshold.

> thanks,
> rui
>> Alhtough, as I mention, I believe with the current generic trip types,
>> this situation can be covered already.
>>  Besides, I believe
>> 'forced-shutdown' does not sound a descriptive enough though. I would
>> suggest something more specific, say 'hardware-shutdown'.
>>
>> > >
>> > > thanks,
>> > > rui
>> > >
>> > > > It's a good option.
>> > > > I can send a patch,but I don't know whether the thermal maintainers will
>> > > > accept it.
>> > > >
>> > > > Maybe,they have a better way to suggest it.:-)
>> > > >
>> > > >
>> > > > PS:I will sent a new patch If I still have no received their suggestions
>> > > > in two days.
>> > > >
>> > > > > Heiko
>> > > > >
>> > > > >
>> > > > > [0] in a separate patch, changing
>> > > > > - thermal_trip_type enum in include/linux/thermal.h
>> > > > > - trip_types mapping in drivers/thermal/of-thermal.c
>> > > > > - Documentation/devicetree/bindings/thermal/thermal.txt
>> > > > >
>> > > > >> +
>> > > > >> +Example:
>> > > > >> +tsadc: tsadc at ff280000 {
>> > > > >> +    compatible = "rockchip,rk3288-tsadc";
>> > > > >> +    reg = <0xff280000 0x100>;
>> > > > >> +    interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
>> > > > >> +    clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
>> > > > >> +    clock-names = "tsadc", "apb_pclk";
>> > > > >> +};
>> >
>>
>
>



-- 
Eduardo Bezerra Valentin

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 3/4] ARM: dts: add main Thermal info to rk3288
  2014-09-09 11:37     ` Heiko Stübner
@ 2014-09-10  2:49       ` Caesar Wang
  -1 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-10  2:49 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: rui.zhang, edubezval, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov

Hi Heiko,

在 2014年09月09日 19:37, Heiko Stübner 写道:
> Am Mittwoch, 3. September 2014, 10:10:38 schrieb Caesar Wang:
>> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>> ---
>>   arch/arm/boot/dts/rk3288.dtsi | 18 ++++++++++++++++++
>>   1 file changed, 18 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
>> index 36be7bb..3d672e3 100644
>> --- a/arch/arm/boot/dts/rk3288.dtsi
>> +++ b/arch/arm/boot/dts/rk3288.dtsi
>> @@ -224,6 +224,17 @@
>>   		status = "disabled";
>>   	};
>>
>> +	tsadc: tsadc@ff280000 {
> please keep the list of nodes sorted by register address. So when looking at
> my v3.18-next/dts branch, it should be after uart4: serial@ff1c0000 and before
> usb_host0_ehci: usb@ff500000 .
>

oh...,I will fix it.
>> +		compatible = "rockchip,rk3288-tsadc";
>> +		reg = <0xff280000 0x100>;
>> +		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
>> +		clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
>> +		clock-names = "tsadc", "apb_pclk";
>> +		pinctrl-names = "default";
>> +		pinctrl-1 = <&tsadc_int>;
>> +		status = "disabled";
>> +	};
>> +
>>   	/* NOTE: ohci@ff520000 doesn't actually work on hardware */
>>
>>   	usb_hsic: usb@ff5c0000 {
>> @@ -611,5 +622,12 @@
>>   				rockchip,pins = <5 15 3 &pcfg_pull_none>;
>>   			};
>>   		};
>> +
>> +		tsadc {
>> +			tsadc_int: tsadc-int {
>> +				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
>> +			};
>> +		};
> After looking this up in the schematics I see that this is the
> overtemperature-protection output pin ... labeled OTP_OUT.
> So I'd think the pinconfig should reflect this pin-name, especially as tsadc-int
> suggests, that this would be an interrupt leading into the tsadc, while in
> fact it is an output to a separate circuit.
>
Maybe,I guess  your mean as the follows .
Please correct it and  Laugh out if I got it wrong.

tsadc {
             otp_out: otp-out {
                 rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_none>;
             };

             tsadc_int: tsadc-int {
                 rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>;
             };
         };
Then,I deal with the otp_out in thermal driver.
I believe The "otp_out" will restart board if it's a high active.

tsadc_int: tsadc-int {
+				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
+			};

But,I think the about will be implemented in thermal driver.
> Heiko
>
>
>

-- 
Best regards,
Caesar



^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 3/4] ARM: dts: add main Thermal info to rk3288
@ 2014-09-10  2:49       ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-10  2:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Heiko,

? 2014?09?09? 19:37, Heiko St?bner ??:
> Am Mittwoch, 3. September 2014, 10:10:38 schrieb Caesar Wang:
>> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>> ---
>>   arch/arm/boot/dts/rk3288.dtsi | 18 ++++++++++++++++++
>>   1 file changed, 18 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
>> index 36be7bb..3d672e3 100644
>> --- a/arch/arm/boot/dts/rk3288.dtsi
>> +++ b/arch/arm/boot/dts/rk3288.dtsi
>> @@ -224,6 +224,17 @@
>>   		status = "disabled";
>>   	};
>>
>> +	tsadc: tsadc at ff280000 {
> please keep the list of nodes sorted by register address. So when looking at
> my v3.18-next/dts branch, it should be after uart4: serial at ff1c0000 and before
> usb_host0_ehci: usb at ff500000 .
>

oh...,I will fix it.
>> +		compatible = "rockchip,rk3288-tsadc";
>> +		reg = <0xff280000 0x100>;
>> +		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
>> +		clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
>> +		clock-names = "tsadc", "apb_pclk";
>> +		pinctrl-names = "default";
>> +		pinctrl-1 = <&tsadc_int>;
>> +		status = "disabled";
>> +	};
>> +
>>   	/* NOTE: ohci at ff520000 doesn't actually work on hardware */
>>
>>   	usb_hsic: usb at ff5c0000 {
>> @@ -611,5 +622,12 @@
>>   				rockchip,pins = <5 15 3 &pcfg_pull_none>;
>>   			};
>>   		};
>> +
>> +		tsadc {
>> +			tsadc_int: tsadc-int {
>> +				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
>> +			};
>> +		};
> After looking this up in the schematics I see that this is the
> overtemperature-protection output pin ... labeled OTP_OUT.
> So I'd think the pinconfig should reflect this pin-name, especially as tsadc-int
> suggests, that this would be an interrupt leading into the tsadc, while in
> fact it is an output to a separate circuit.
>
Maybe,I guess  your mean as the follows .
Please correct it and  Laugh out if I got it wrong.

tsadc {
             otp_out: otp-out {
                 rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_none>;
             };

             tsadc_int: tsadc-int {
                 rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>;
             };
         };
Then,I deal with the otp_out in thermal driver.
I believe The "otp_out" will restart board if it's a high active.

tsadc_int: tsadc-int {
+				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
+			};

But,I think the about will be implemented in thermal driver.
> Heiko
>
>
>

-- 
Best regards,
Caesar

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 1/4] thermal: rockchip: add driver for thermal
  2014-08-30 20:09     ` Eduardo Valentin
@ 2014-09-10  4:39       ` Caesar Wang
  -1 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-10  4:39 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: heiko, rui.zhang, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov, zhaoyifeng

Dear Eduardo,

I'm  sorry for it.
I just received this message.Maybe my mailbox has a problem.

Thank you for your comments.

在 2014年08月31日 04:09, Eduardo Valentin 写道:
> Hello Ceasar,
>
> On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
>> Thermal is TS-ADC Controller module supports
>> user-defined mode and automatic mode.
>>
>> User-defined mode refers,TSADC all the control signals entirely by
>> software writing to register for direct control.
>>
>> Automaic mode refers to the module automatically poll TSADC output,
>> and the results were checked.If you find that the temperature High
>> in a period of time,an interrupt is generated to the processor
>> down-measures taken;if the temperature over a period of time High,
>> the resulting TSHUT gave CRU module,let it reset the entire chip,
>> or via GPIO give PMIC.
>>
>> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
>> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>> ---
>>   drivers/thermal/Kconfig            |   9 +
>>   drivers/thermal/Makefile           |   1 +
>>   drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
>>   3 files changed, 679 insertions(+)
>>   create mode 100644 drivers/thermal/rockchip_thermal.c
>>
>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>> index f9a1386..a00aa1e 100644
>> --- a/drivers/thermal/Kconfig
>> +++ b/drivers/thermal/Kconfig
>> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
>>   	  Enable this to plug the SPEAr thermal sensor driver into the Linux
>>   	  thermal framework.
>>   
>> +config ROCKCHIP_THERMAL
>> +	tristate "Rockchip thermal driver"
>> +	depends on ARCH_ROCKCHIP
>> +	help
>> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
>> +	  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 RCAR_THERMAL
>>   	tristate "Renesas R-Car thermal driver"
>>   	depends on ARCH_SHMOBILE || COMPILE_TEST
>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>> index de0636a..b48b817 100644
>> --- a/drivers/thermal/Makefile
>> +++ b/drivers/thermal/Makefile
>> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
>>   
>>   # platform thermal drivers
>>   obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
>> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
>>   obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
>>   obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
>>   obj-y				+= samsung/
>> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
>> new file mode 100644
>> index 0000000..011f387
>> --- /dev/null
>> +++ b/drivers/thermal/rockchip_thermal.c
>> @@ -0,0 +1,669 @@
>> +/*
>> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
>> + *
>> + * 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/clk.h>
>> +#include <linux/io.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/cpu_cooling.h>
>> +#include "thermal_core.h"
> Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
> sufficient?
>

yes, I will use linux/thermal.h.
>> +
>> +enum rockchip_thermal_trip {
>> +	ROCKCHIP_TRIP_PASSIVE,
>> +	ROCKCHIP_TRIP_CRITICAL,
>> +	ROCKCHIP_TRIP_NUM,
>> +};
>> +
> Why do you need your own trip types?
>
>> +struct rockchip_thermal_data {
>> +	const struct rockchip_tsadc_platform_data *pdata;
>> +	struct thermal_zone_device *tz;
>> +	struct thermal_cooling_device *cdev;
>> +	enum thermal_device_mode mode;
>> +	void __iomem *regs;
>> +
>> +	signed long temp_passive;
>> +	signed long temp_critical;
>> +	signed long temp_force_shut;
>> +	signed long alarm_temp;
>> +	signed long last_temp;
>> +	bool irq_enabled;
>> +	int irq;
>> +	struct clk *clk;
>> +	struct clk *pclk;
>> +};
>> +
>> +struct rockchip_tsadc_platform_data {
>> +	u8 irq_en;
>> +	signed long temp_passive;
>> +	signed long temp_critical;
>> +	signed long temp_force_shut;
>> +	int passive_delay;
>> +	int polling_delay;
>> +
>> +	int (*irq_handle)(void __iomem *reg);
>> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
>> +	int (*control)(void __iomem *reg, bool on);
>> +	u32 (*code_to_temp)(int temp);
>> +	u32 (*temp_to_code)(int temp);
>> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
>> +};
>> +
>> +/*TSADC V2 Sensor info define:*/
>> +#define TSADCV2_AUTO_CON			0x04
>> +#define TSADCV2_INT_EN				0x08
>> +#define TSADCV2_INT_PD				0x0c
>> +#define TSADCV2_DATA1				0x24
>> +#define TSADCV2_COMP1_INT			0x34
>> +#define TSADCV2_COMP1_SHUT			0x44
>> +#define TSADCV2_AUTO_PERIOD			0x68
>> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
>> +
>> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
>> +#define TSADCV2_AUTO_EN				(1 << 0)
>> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
>> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
>> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
>> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
>> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
>> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
>> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
>> +
> The above bits can be defined with BIT() macro, right?

Yes. The Bit() will be more resonable..
>   Something like:
> +#define TSADCV2_INT_SRC1_STATUS			BIT(1)
>
>
>> +#define TSADCV2_DATA_MASK			0xfff
>> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
>> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
>> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
>> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
>> +
>> +struct tsadc_table {
>> +	int code;
>> +	int temp;
>> +};
>> +
>> +static const struct tsadc_table v2_code_table[] = {
>> +	{TSADCV2_DATA_MASK, -40},
>> +	{3800, -40},
>> +	{3792, -35},
>> +	{3783, -30},
>> +	{3774, -25},
>> +	{3765, -20},
>> +	{3756, -15},
>> +	{3747, -10},
>> +	{3737, -5},
>> +	{3728, 0},
>> +	{3718, 5},
>> +	{3708, 10},
>> +	{3698, 15},
>> +	{3688, 20},
>> +	{3678, 25},
>> +	{3667, 30},
>> +	{3656, 35},
>> +	{3645, 40},
>> +	{3634, 45},
>> +	{3623, 50},
>> +	{3611, 55},
>> +	{3600, 60},
>> +	{3588, 65},
>> +	{3575, 70},
>> +	{3563, 75},
>> +	{3550, 80},
>> +	{3537, 85},
>> +	{3524, 90},
>> +	{3510, 95},
>> +	{3496, 100},
>> +	{3482, 105},
>> +	{3467, 110},
>> +	{3452, 115},
>> +	{3437, 120},
>> +	{3421, 125},
>> +	{0, 125},
>> +};
>> +
>> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
>> +{
>> +	u32 val;
>> +
>> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
>> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
> Why do you need to clear bit 8? Why hardcoded?

The bit 8 set 0 to clear the interrupt.

>> +
>> +	return 0;
>> +}
>> +
>> +static u32 rk_tsadcv2_temp_to_code(int temp)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>> +		if (temp <= v2_code_table[i].temp && temp >
>> +		    v2_code_table[i - 1].temp)
>> +			return v2_code_table[i].code;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static u32 rk_tsadcv2_code_to_temp(int code)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>> +		if (code <= v2_code_table[i].code && code >
>> +		    v2_code_table[i + 1].code){
>> +			return v2_code_table[i].temp;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
> I know the table is not something too big, but considering it is ordered
> by either ADC value code or by temp, at least one of the above searching function
> may be more efficient, right?
Yes, use the point will be more efficient.
>> +
>> +static int rk_tsadcv2_initialize(void __iomem *regs,
>> +				 signed long temp_force_shut)
>> +{
>> +	int shutdown_value;
>> +
>> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
>> +	/* Enable measurements at ~ 10 Hz */
> Does it leave the sampling clock at 10Hz?
yes.
> Is this clock exposed via
> clock framework?

The clock is divided by data->clk.
>
>> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
>> +		       TSADCV2_AUTO_PERIOD_HT);
>> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
>> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
>> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
>> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
>> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
>> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
>> +		       TSADCV2_INT_EN);
>> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
>> +		       TSADCV2_AUTO_CON);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
>> +{
>> +	u32 val;
>> +
>> +	if (on) {
>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
>> +	} else {
>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
>> +			       regs + TSADCV2_AUTO_CON);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
>> +{
>> +	int alarm_value;
>> +
>> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
>> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
>> +}
>> +
>> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
>> +	.irq_en = 1,
>> +	.temp_passive = 85000,
>> +	.temp_critical = 100000,
>> +	.temp_force_shut = 120000,
>> +	.passive_delay = 2000,
>> +	.polling_delay = 1000,
>> +	.irq_handle = rk_tsadcv2_irq_handle,
>> +	.initialize = rk_tsadcv2_initialize,
>> +	.control = rk_tsadcv2_control,
>> +	.code_to_temp = rk_tsadcv2_code_to_temp,
>> +	.temp_to_code = rk_tsadcv2_temp_to_code,
>> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
>> +};
> shall the above struct be also static?
OK.
>> +
>> +static const struct of_device_id of_rockchip_thermal_match[] = {
>> +	{
>> +		.compatible = "rockchip,rk3288-tsadc",
>> +		.data = (void *)&rk3288_tsadc_data,
>> +	},
>> +	{ /* end */ },
>> +};
>> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
>> +
>> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
>> +				    signed long alarm_temp)
>> +{
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +
>> +	data->alarm_temp = alarm_temp;
>> +	if (p_tsadc_data->set_alarm_temp)
>> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
>> +}
>> +
>> +static int rockchip_get_temp(struct thermal_zone_device *tz,
>> +			     unsigned long *temp)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +	u32 val;
>> +
>> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
>> +	*temp = p_tsadc_data->code_to_temp(val);
>> +
>> +	/* Update alarm value to next higher trip point */
>> +	if (data->alarm_temp == data->temp_passive && *temp >=
>> +	    data->temp_passive)
>> +		rockchip_set_alarm_temp(data, data->temp_critical);
>> +
>> +	if (data->alarm_temp == data->temp_critical && *temp <
>> +	    data->temp_passive) {
>> +		rockchip_set_alarm_temp(data, data->temp_passive);
>> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
>> +			data->alarm_temp / 1000);
>> +	}
>> +
>> +	if (*temp != data->last_temp) {
>> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
>> +		data->last_temp = *temp;
>> +	}
>> +
>> +	/* Reenable alarm IRQ if temperature below alarm temperature */
>> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
>> +		data->irq_enabled = true;
>> +		enable_irq(data->irq);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
>> +{
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +
>> +	if (p_tsadc_data->initialize)
>> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
>> +	rockchip_set_alarm_temp(data, data->temp_passive);
>> +
>> +	return 0;
>> +}
>> +
>> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
>> +				     bool on)
>> +{
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +
>> +	if (p_tsadc_data->control)
>> +		p_tsadc_data->control(data->regs, on);
>> +
>> +	if (on) {
>> +		data->irq_enabled = true;
>> +		data->mode = THERMAL_DEVICE_ENABLED;
>> +	} else {
>> +		data->irq_enabled = false;
>> +		data->mode = THERMAL_DEVICE_DISABLED;
>> +	}
>> +}
>> +
>> +static int rockchip_get_mode(struct thermal_zone_device *tz,
>> +			     enum thermal_device_mode *mode)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +
>> +	*mode = data->mode;
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_set_mode(struct thermal_zone_device *tz,
>> +			     enum thermal_device_mode mode)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +
>> +	if (mode == THERMAL_DEVICE_ENABLED) {
>> +		tz->polling_delay = p_tsadc_data->polling_delay;
>> +		tz->passive_delay = p_tsadc_data->passive_delay;
>> +		if (!data->irq_enabled) {
>> +			data->irq_enabled = true;
>> +			enable_irq(data->irq);
>> +		}
>> +	} else {
>> +		tz->polling_delay = 0;
>> +		tz->passive_delay = 0;
>> +		if (data->irq_enabled) {
>> +			disable_irq(data->irq);
>> +			data->irq_enabled = false;
>> +		}
>> +	}
>> +
>> +	data->mode = mode;
>> +	thermal_zone_device_update(tz);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
>> +				  enum thermal_trip_type *type)
>> +{
>> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
>> +		 THERMAL_TRIP_CRITICAL;
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
>> +				  unsigned long *temp)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +
>> +	*temp = data->temp_critical;
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
>> +				  unsigned long *temp)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +
>> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
>> +		 data->temp_critical;
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
>> +				  unsigned long temp)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +
>> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
>> +		return -EPERM;
>> +
>> +	data->temp_passive = temp;
>> +	rockchip_set_alarm_temp(data, temp);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_bind(struct thermal_zone_device *tz,
>> +			 struct thermal_cooling_device *cdev)
>> +{
>> +	int ret;
>> +
>> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
>> +					       THERMAL_NO_LIMIT,
>> +					       THERMAL_NO_LIMIT);
>> +	if (ret) {
>> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>> +			tz->type, cdev->type, ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_unbind(struct thermal_zone_device *tz,
>> +			   struct thermal_cooling_device *cdev)
>> +{
>> +	int ret;
>> +
>> +	ret = thermal_zone_unbind_cooling_device(tz,
>> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
>> +	if (ret) {
>> +		dev_err(&tz->device,
>> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
>> +			cdev->type, ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
> The method of binding and unbinding used above requires you to check if
> you are binding to the right cdev. If in your system you register more
> than one cdev, say someone loads the power supply core, which in turns
> register a cooling device for charging, your thermal zone will bind it
> to TRIP_PASSIVE. It will happen to any cooling device that eventually
> gets registered to the thermal framework. Is that the desired outcome?

Yes,I will use the generic trip points in the dts and fix it in the 
thermal driver.
> If not, you may want to compare the paramenter cdev to your data->cdev.
>
>> +
>> +static struct thermal_zone_device_ops rockchip_tz_ops = {
>> +	.bind = rockchip_bind,
>> +	.unbind = rockchip_unbind,
>> +	.get_temp = rockchip_get_temp,
>> +	.get_mode = rockchip_get_mode,
>> +	.set_mode = rockchip_set_mode,
>> +	.get_trip_type = rockchip_get_trip_type,
>> +	.get_trip_temp = rockchip_get_trip_temp,
>> +	.get_crit_temp = rockchip_get_crit_temp,
>> +	.set_trip_temp = rockchip_set_trip_temp,
>> +};
>> +
>> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
>> +{
>> +	struct rockchip_thermal_data *data = data;
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +
>> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
>> +		data->alarm_temp / 1000);
>> +
>> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
>> +		p_tsadc_data->irq_handle(data->regs);
>> +
>> +	thermal_zone_device_update(data->tz);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static int rockchip_thermal_probe(struct platform_device *pdev)
>> +{
>> +	struct rockchip_thermal_data *data;
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
>> +	struct cpumask clip_cpus;
>> +	struct resource *res;
>> +	const struct of_device_id *match;
>> +	int ret, temp;
>> +
>> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
>> +			    GFP_KERNEL);
>> +	if (!data)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(data->regs)) {
>> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
>> +			data->regs);
>> +		return PTR_ERR(data->regs);
>> +	}
>> +
>> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
>> +	if (!match)
>> +		return -ENXIO;
>> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
>> +	if (!data->pdata)
>> +		return -EINVAL;
>> +	p_tsadc_data = data->pdata;
>> +
>> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
>> +	if (IS_ERR(data->clk)) {
>> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
>> +		return PTR_ERR(data->clk);
>> +	}
>> +
>> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
>> +	if (IS_ERR(data->pclk)) {
>> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
>> +		return PTR_ERR(data->pclk);
>> +	}
>> +
>> +	/*
>> +	* Use a default of 10KHz for the converter clock.
>> +	* This may become user-configurable in the future.
>> +	*/
>> +	ret = clk_set_rate(data->clk, 10000);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = clk_prepare_enable(data->clk);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
>> +		goto err_clk;
>> +	}
>> +
>> +	ret = clk_prepare_enable(data->pclk);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "failed to enable pclk\n");
>> +		goto err_pclk;
>> +	}
>> +
>> +	platform_set_drvdata(pdev, data);
>> +
>> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
>> +		dev_warn(&pdev->dev,
>> +			 "Missing default passive temp property in the DT.\n");
>> +		data->temp_passive = p_tsadc_data->temp_passive;
>> +	} else {
>> +		data->temp_passive = temp;
>> +	}
>> +
>> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
>> +		dev_warn(&pdev->dev,
>> +			 "Missing default critical temp property in the DT.\n");
>> +		data->temp_critical = p_tsadc_data->temp_critical;
>> +	} else {
>> +		data->temp_critical = temp;
>> +	}
>> +
>> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
>> +		dev_warn(&pdev->dev,
>> +			 "Missing default force shut down temp property in the DT.\n");
>> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
>> +	} else {
>> +		data->temp_force_shut = temp;
>> +	}
>> +
>> +	cpumask_set_cpu(0, &clip_cpus);
>> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
>> +	if (IS_ERR(data->cdev)) {
>> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
>> +		goto disable_clk;
>> +	}
>> +
>> +	data->tz = thermal_zone_device_register("rockchip_thermal",
>> +						ROCKCHIP_TRIP_NUM,
>> +						0, data,
>> +						&rockchip_tz_ops, NULL,
>> +						p_tsadc_data->passive_delay,
>> +						p_tsadc_data->polling_delay);
>> +
>> +	if (IS_ERR(data->tz)) {
>> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
>> +		goto fail_cpufreq_register;
>> +	}
>> +
>> +	if (p_tsadc_data->irq_en) {
>> +		data->irq = platform_get_irq(pdev, 0);
>> +		if (data->irq < 0) {
>> +			dev_err(&pdev->dev, "no irq resource?\n");
>> +			goto fail_irq;
>> +		}
>> +
>> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
>> +				rockchip_thermal_alarm_irq_thread,
>> +				IRQF_ONESHOT, "rockchip_thermal", data);
>> +		if (ret < 0) {
>> +			dev_err(&pdev->dev,
>> +				"failed to request tsadc irq: %d\n", ret);
>> +			goto fail_thermal_unregister;
>> +		}
>> +	}
>> +
>> +	rockchip_thermal_initialize(data);
>> +	rockchip_thermal_control(data, true);
>> +
>> +	return 0;
>> +
>> +fail_thermal_unregister:
>> +	thermal_zone_device_unregister(data->tz);
>> +fail_irq:
>> +fail_cpufreq_register:
>> +	cpufreq_cooling_unregister(data->cdev);
>> +disable_clk:
>> +err_pclk:
>> +	clk_disable_unprepare(data->pclk);
>> +err_clk:
>> +	clk_disable_unprepare(data->clk);
>> +
>> +	return ret;
>> +}
>> +
>> +static int rockchip_thermal_remove(struct platform_device *pdev)
>> +{
>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>> +
>> +	rockchip_thermal_control(data, false);
>> +
>> +	thermal_zone_device_unregister(data->tz);
>> +	cpufreq_cooling_unregister(data->cdev);
>> +	cpufreq_cooling_unregister(data->cdev);
>> +
> The above call is duplicated.

OK.
>> +	clk_disable_unprepare(data->clk);
>> +	clk_disable_unprepare(data->pclk);
>> +
>> +	return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +static int rockchip_thermal_suspend(struct device *dev)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>> +
>> +	rockchip_thermal_control(data, false);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_thermal_resume(struct device *dev)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>> +
>> +	rockchip_thermal_initialize(data);
>> +	rockchip_thermal_control(data, true);
>> +
>> +	return 0;
>> +}
> Would you need to manage your clocks too in the suspend resume path
> (data->clk and data->pclk)?
yes.
Usually,it's need disable to save power.
>> +#endif
>> +
>> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
>> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
>> +
>> +static struct platform_driver rockchip_thermal_driver = {
>> +	.driver = {
>> +		   .name = "rockchip-thermal",
>> +		   .owner = THIS_MODULE,
>> +		   .pm = &rockchip_thermal_pm_ops,
>> +		   .of_match_table = of_rockchip_thermal_match,
>> +		   },
>> +	.probe = rockchip_thermal_probe,
>> +	.remove = rockchip_thermal_remove,
>> +};
>> +
>> +module_platform_driver(rockchip_thermal_driver);
>> +
>> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
>> +MODULE_AUTHOR("Rockchip, Inc.");
>> +MODULE_LICENSE("GPL");
> Your file header states GPL version two. Thus I suppose you meant:
> +MODULE_LICENSE("GPL v2");
>
> right?
>
> Check include/linux/module.h for further clarifications.

But I think the  "GPL"  is support for thr GNU Public License v2 or later.
I will fix GPL v2 if I get it wrong.

>> +MODULE_ALIAS("platform:rockchip-thermal");
>> -- 
>> 1.9.1
>>
>>
> BR,
>
> Eduardo Valentin
>
>
>

-- 
Best regards,
Caesar



^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 1/4] thermal: rockchip: add driver for thermal
@ 2014-09-10  4:39       ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-10  4:39 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Eduardo,

I'm  sorry for it.
I just received this message.Maybe my mailbox has a problem.

Thank you for your comments.

? 2014?08?31? 04:09, Eduardo Valentin ??:
> Hello Ceasar,
>
> On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
>> Thermal is TS-ADC Controller module supports
>> user-defined mode and automatic mode.
>>
>> User-defined mode refers,TSADC all the control signals entirely by
>> software writing to register for direct control.
>>
>> Automaic mode refers to the module automatically poll TSADC output,
>> and the results were checked.If you find that the temperature High
>> in a period of time,an interrupt is generated to the processor
>> down-measures taken;if the temperature over a period of time High,
>> the resulting TSHUT gave CRU module,let it reset the entire chip,
>> or via GPIO give PMIC.
>>
>> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
>> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>> ---
>>   drivers/thermal/Kconfig            |   9 +
>>   drivers/thermal/Makefile           |   1 +
>>   drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
>>   3 files changed, 679 insertions(+)
>>   create mode 100644 drivers/thermal/rockchip_thermal.c
>>
>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>> index f9a1386..a00aa1e 100644
>> --- a/drivers/thermal/Kconfig
>> +++ b/drivers/thermal/Kconfig
>> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
>>   	  Enable this to plug the SPEAr thermal sensor driver into the Linux
>>   	  thermal framework.
>>   
>> +config ROCKCHIP_THERMAL
>> +	tristate "Rockchip thermal driver"
>> +	depends on ARCH_ROCKCHIP
>> +	help
>> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
>> +	  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 RCAR_THERMAL
>>   	tristate "Renesas R-Car thermal driver"
>>   	depends on ARCH_SHMOBILE || COMPILE_TEST
>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>> index de0636a..b48b817 100644
>> --- a/drivers/thermal/Makefile
>> +++ b/drivers/thermal/Makefile
>> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
>>   
>>   # platform thermal drivers
>>   obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
>> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
>>   obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
>>   obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
>>   obj-y				+= samsung/
>> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
>> new file mode 100644
>> index 0000000..011f387
>> --- /dev/null
>> +++ b/drivers/thermal/rockchip_thermal.c
>> @@ -0,0 +1,669 @@
>> +/*
>> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
>> + *
>> + * 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/clk.h>
>> +#include <linux/io.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/cpu_cooling.h>
>> +#include "thermal_core.h"
> Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
> sufficient?
>

yes, I will use linux/thermal.h.
>> +
>> +enum rockchip_thermal_trip {
>> +	ROCKCHIP_TRIP_PASSIVE,
>> +	ROCKCHIP_TRIP_CRITICAL,
>> +	ROCKCHIP_TRIP_NUM,
>> +};
>> +
> Why do you need your own trip types?
>
>> +struct rockchip_thermal_data {
>> +	const struct rockchip_tsadc_platform_data *pdata;
>> +	struct thermal_zone_device *tz;
>> +	struct thermal_cooling_device *cdev;
>> +	enum thermal_device_mode mode;
>> +	void __iomem *regs;
>> +
>> +	signed long temp_passive;
>> +	signed long temp_critical;
>> +	signed long temp_force_shut;
>> +	signed long alarm_temp;
>> +	signed long last_temp;
>> +	bool irq_enabled;
>> +	int irq;
>> +	struct clk *clk;
>> +	struct clk *pclk;
>> +};
>> +
>> +struct rockchip_tsadc_platform_data {
>> +	u8 irq_en;
>> +	signed long temp_passive;
>> +	signed long temp_critical;
>> +	signed long temp_force_shut;
>> +	int passive_delay;
>> +	int polling_delay;
>> +
>> +	int (*irq_handle)(void __iomem *reg);
>> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
>> +	int (*control)(void __iomem *reg, bool on);
>> +	u32 (*code_to_temp)(int temp);
>> +	u32 (*temp_to_code)(int temp);
>> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
>> +};
>> +
>> +/*TSADC V2 Sensor info define:*/
>> +#define TSADCV2_AUTO_CON			0x04
>> +#define TSADCV2_INT_EN				0x08
>> +#define TSADCV2_INT_PD				0x0c
>> +#define TSADCV2_DATA1				0x24
>> +#define TSADCV2_COMP1_INT			0x34
>> +#define TSADCV2_COMP1_SHUT			0x44
>> +#define TSADCV2_AUTO_PERIOD			0x68
>> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
>> +
>> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
>> +#define TSADCV2_AUTO_EN				(1 << 0)
>> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
>> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
>> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
>> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
>> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
>> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
>> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
>> +
> The above bits can be defined with BIT() macro, right?

Yes. The Bit() will be more resonable..
>   Something like:
> +#define TSADCV2_INT_SRC1_STATUS			BIT(1)
>
>
>> +#define TSADCV2_DATA_MASK			0xfff
>> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
>> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
>> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
>> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
>> +
>> +struct tsadc_table {
>> +	int code;
>> +	int temp;
>> +};
>> +
>> +static const struct tsadc_table v2_code_table[] = {
>> +	{TSADCV2_DATA_MASK, -40},
>> +	{3800, -40},
>> +	{3792, -35},
>> +	{3783, -30},
>> +	{3774, -25},
>> +	{3765, -20},
>> +	{3756, -15},
>> +	{3747, -10},
>> +	{3737, -5},
>> +	{3728, 0},
>> +	{3718, 5},
>> +	{3708, 10},
>> +	{3698, 15},
>> +	{3688, 20},
>> +	{3678, 25},
>> +	{3667, 30},
>> +	{3656, 35},
>> +	{3645, 40},
>> +	{3634, 45},
>> +	{3623, 50},
>> +	{3611, 55},
>> +	{3600, 60},
>> +	{3588, 65},
>> +	{3575, 70},
>> +	{3563, 75},
>> +	{3550, 80},
>> +	{3537, 85},
>> +	{3524, 90},
>> +	{3510, 95},
>> +	{3496, 100},
>> +	{3482, 105},
>> +	{3467, 110},
>> +	{3452, 115},
>> +	{3437, 120},
>> +	{3421, 125},
>> +	{0, 125},
>> +};
>> +
>> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
>> +{
>> +	u32 val;
>> +
>> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
>> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
> Why do you need to clear bit 8? Why hardcoded?

The bit 8 set 0 to clear the interrupt.

>> +
>> +	return 0;
>> +}
>> +
>> +static u32 rk_tsadcv2_temp_to_code(int temp)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>> +		if (temp <= v2_code_table[i].temp && temp >
>> +		    v2_code_table[i - 1].temp)
>> +			return v2_code_table[i].code;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static u32 rk_tsadcv2_code_to_temp(int code)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>> +		if (code <= v2_code_table[i].code && code >
>> +		    v2_code_table[i + 1].code){
>> +			return v2_code_table[i].temp;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
> I know the table is not something too big, but considering it is ordered
> by either ADC value code or by temp, at least one of the above searching function
> may be more efficient, right?
Yes, use the point will be more efficient.
>> +
>> +static int rk_tsadcv2_initialize(void __iomem *regs,
>> +				 signed long temp_force_shut)
>> +{
>> +	int shutdown_value;
>> +
>> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
>> +	/* Enable measurements at ~ 10 Hz */
> Does it leave the sampling clock at 10Hz?
yes.
> Is this clock exposed via
> clock framework?

The clock is divided by data->clk.
>
>> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
>> +		       TSADCV2_AUTO_PERIOD_HT);
>> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
>> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
>> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
>> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
>> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
>> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
>> +		       TSADCV2_INT_EN);
>> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
>> +		       TSADCV2_AUTO_CON);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
>> +{
>> +	u32 val;
>> +
>> +	if (on) {
>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
>> +	} else {
>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
>> +			       regs + TSADCV2_AUTO_CON);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
>> +{
>> +	int alarm_value;
>> +
>> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
>> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
>> +}
>> +
>> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
>> +	.irq_en = 1,
>> +	.temp_passive = 85000,
>> +	.temp_critical = 100000,
>> +	.temp_force_shut = 120000,
>> +	.passive_delay = 2000,
>> +	.polling_delay = 1000,
>> +	.irq_handle = rk_tsadcv2_irq_handle,
>> +	.initialize = rk_tsadcv2_initialize,
>> +	.control = rk_tsadcv2_control,
>> +	.code_to_temp = rk_tsadcv2_code_to_temp,
>> +	.temp_to_code = rk_tsadcv2_temp_to_code,
>> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
>> +};
> shall the above struct be also static?
OK.
>> +
>> +static const struct of_device_id of_rockchip_thermal_match[] = {
>> +	{
>> +		.compatible = "rockchip,rk3288-tsadc",
>> +		.data = (void *)&rk3288_tsadc_data,
>> +	},
>> +	{ /* end */ },
>> +};
>> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
>> +
>> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
>> +				    signed long alarm_temp)
>> +{
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +
>> +	data->alarm_temp = alarm_temp;
>> +	if (p_tsadc_data->set_alarm_temp)
>> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
>> +}
>> +
>> +static int rockchip_get_temp(struct thermal_zone_device *tz,
>> +			     unsigned long *temp)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +	u32 val;
>> +
>> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
>> +	*temp = p_tsadc_data->code_to_temp(val);
>> +
>> +	/* Update alarm value to next higher trip point */
>> +	if (data->alarm_temp == data->temp_passive && *temp >=
>> +	    data->temp_passive)
>> +		rockchip_set_alarm_temp(data, data->temp_critical);
>> +
>> +	if (data->alarm_temp == data->temp_critical && *temp <
>> +	    data->temp_passive) {
>> +		rockchip_set_alarm_temp(data, data->temp_passive);
>> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
>> +			data->alarm_temp / 1000);
>> +	}
>> +
>> +	if (*temp != data->last_temp) {
>> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
>> +		data->last_temp = *temp;
>> +	}
>> +
>> +	/* Reenable alarm IRQ if temperature below alarm temperature */
>> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
>> +		data->irq_enabled = true;
>> +		enable_irq(data->irq);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
>> +{
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +
>> +	if (p_tsadc_data->initialize)
>> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
>> +	rockchip_set_alarm_temp(data, data->temp_passive);
>> +
>> +	return 0;
>> +}
>> +
>> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
>> +				     bool on)
>> +{
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +
>> +	if (p_tsadc_data->control)
>> +		p_tsadc_data->control(data->regs, on);
>> +
>> +	if (on) {
>> +		data->irq_enabled = true;
>> +		data->mode = THERMAL_DEVICE_ENABLED;
>> +	} else {
>> +		data->irq_enabled = false;
>> +		data->mode = THERMAL_DEVICE_DISABLED;
>> +	}
>> +}
>> +
>> +static int rockchip_get_mode(struct thermal_zone_device *tz,
>> +			     enum thermal_device_mode *mode)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +
>> +	*mode = data->mode;
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_set_mode(struct thermal_zone_device *tz,
>> +			     enum thermal_device_mode mode)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +
>> +	if (mode == THERMAL_DEVICE_ENABLED) {
>> +		tz->polling_delay = p_tsadc_data->polling_delay;
>> +		tz->passive_delay = p_tsadc_data->passive_delay;
>> +		if (!data->irq_enabled) {
>> +			data->irq_enabled = true;
>> +			enable_irq(data->irq);
>> +		}
>> +	} else {
>> +		tz->polling_delay = 0;
>> +		tz->passive_delay = 0;
>> +		if (data->irq_enabled) {
>> +			disable_irq(data->irq);
>> +			data->irq_enabled = false;
>> +		}
>> +	}
>> +
>> +	data->mode = mode;
>> +	thermal_zone_device_update(tz);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
>> +				  enum thermal_trip_type *type)
>> +{
>> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
>> +		 THERMAL_TRIP_CRITICAL;
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
>> +				  unsigned long *temp)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +
>> +	*temp = data->temp_critical;
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
>> +				  unsigned long *temp)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +
>> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
>> +		 data->temp_critical;
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
>> +				  unsigned long temp)
>> +{
>> +	struct rockchip_thermal_data *data = tz->devdata;
>> +
>> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
>> +		return -EPERM;
>> +
>> +	data->temp_passive = temp;
>> +	rockchip_set_alarm_temp(data, temp);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_bind(struct thermal_zone_device *tz,
>> +			 struct thermal_cooling_device *cdev)
>> +{
>> +	int ret;
>> +
>> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
>> +					       THERMAL_NO_LIMIT,
>> +					       THERMAL_NO_LIMIT);
>> +	if (ret) {
>> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>> +			tz->type, cdev->type, ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_unbind(struct thermal_zone_device *tz,
>> +			   struct thermal_cooling_device *cdev)
>> +{
>> +	int ret;
>> +
>> +	ret = thermal_zone_unbind_cooling_device(tz,
>> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
>> +	if (ret) {
>> +		dev_err(&tz->device,
>> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
>> +			cdev->type, ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
> The method of binding and unbinding used above requires you to check if
> you are binding to the right cdev. If in your system you register more
> than one cdev, say someone loads the power supply core, which in turns
> register a cooling device for charging, your thermal zone will bind it
> to TRIP_PASSIVE. It will happen to any cooling device that eventually
> gets registered to the thermal framework. Is that the desired outcome?

Yes,I will use the generic trip points in the dts and fix it in the 
thermal driver.
> If not, you may want to compare the paramenter cdev to your data->cdev.
>
>> +
>> +static struct thermal_zone_device_ops rockchip_tz_ops = {
>> +	.bind = rockchip_bind,
>> +	.unbind = rockchip_unbind,
>> +	.get_temp = rockchip_get_temp,
>> +	.get_mode = rockchip_get_mode,
>> +	.set_mode = rockchip_set_mode,
>> +	.get_trip_type = rockchip_get_trip_type,
>> +	.get_trip_temp = rockchip_get_trip_temp,
>> +	.get_crit_temp = rockchip_get_crit_temp,
>> +	.set_trip_temp = rockchip_set_trip_temp,
>> +};
>> +
>> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
>> +{
>> +	struct rockchip_thermal_data *data = data;
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>> +
>> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
>> +		data->alarm_temp / 1000);
>> +
>> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
>> +		p_tsadc_data->irq_handle(data->regs);
>> +
>> +	thermal_zone_device_update(data->tz);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static int rockchip_thermal_probe(struct platform_device *pdev)
>> +{
>> +	struct rockchip_thermal_data *data;
>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
>> +	struct cpumask clip_cpus;
>> +	struct resource *res;
>> +	const struct of_device_id *match;
>> +	int ret, temp;
>> +
>> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
>> +			    GFP_KERNEL);
>> +	if (!data)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(data->regs)) {
>> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
>> +			data->regs);
>> +		return PTR_ERR(data->regs);
>> +	}
>> +
>> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
>> +	if (!match)
>> +		return -ENXIO;
>> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
>> +	if (!data->pdata)
>> +		return -EINVAL;
>> +	p_tsadc_data = data->pdata;
>> +
>> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
>> +	if (IS_ERR(data->clk)) {
>> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
>> +		return PTR_ERR(data->clk);
>> +	}
>> +
>> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
>> +	if (IS_ERR(data->pclk)) {
>> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
>> +		return PTR_ERR(data->pclk);
>> +	}
>> +
>> +	/*
>> +	* Use a default of 10KHz for the converter clock.
>> +	* This may become user-configurable in the future.
>> +	*/
>> +	ret = clk_set_rate(data->clk, 10000);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = clk_prepare_enable(data->clk);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
>> +		goto err_clk;
>> +	}
>> +
>> +	ret = clk_prepare_enable(data->pclk);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "failed to enable pclk\n");
>> +		goto err_pclk;
>> +	}
>> +
>> +	platform_set_drvdata(pdev, data);
>> +
>> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
>> +		dev_warn(&pdev->dev,
>> +			 "Missing default passive temp property in the DT.\n");
>> +		data->temp_passive = p_tsadc_data->temp_passive;
>> +	} else {
>> +		data->temp_passive = temp;
>> +	}
>> +
>> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
>> +		dev_warn(&pdev->dev,
>> +			 "Missing default critical temp property in the DT.\n");
>> +		data->temp_critical = p_tsadc_data->temp_critical;
>> +	} else {
>> +		data->temp_critical = temp;
>> +	}
>> +
>> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
>> +		dev_warn(&pdev->dev,
>> +			 "Missing default force shut down temp property in the DT.\n");
>> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
>> +	} else {
>> +		data->temp_force_shut = temp;
>> +	}
>> +
>> +	cpumask_set_cpu(0, &clip_cpus);
>> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
>> +	if (IS_ERR(data->cdev)) {
>> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
>> +		goto disable_clk;
>> +	}
>> +
>> +	data->tz = thermal_zone_device_register("rockchip_thermal",
>> +						ROCKCHIP_TRIP_NUM,
>> +						0, data,
>> +						&rockchip_tz_ops, NULL,
>> +						p_tsadc_data->passive_delay,
>> +						p_tsadc_data->polling_delay);
>> +
>> +	if (IS_ERR(data->tz)) {
>> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
>> +		goto fail_cpufreq_register;
>> +	}
>> +
>> +	if (p_tsadc_data->irq_en) {
>> +		data->irq = platform_get_irq(pdev, 0);
>> +		if (data->irq < 0) {
>> +			dev_err(&pdev->dev, "no irq resource?\n");
>> +			goto fail_irq;
>> +		}
>> +
>> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
>> +				rockchip_thermal_alarm_irq_thread,
>> +				IRQF_ONESHOT, "rockchip_thermal", data);
>> +		if (ret < 0) {
>> +			dev_err(&pdev->dev,
>> +				"failed to request tsadc irq: %d\n", ret);
>> +			goto fail_thermal_unregister;
>> +		}
>> +	}
>> +
>> +	rockchip_thermal_initialize(data);
>> +	rockchip_thermal_control(data, true);
>> +
>> +	return 0;
>> +
>> +fail_thermal_unregister:
>> +	thermal_zone_device_unregister(data->tz);
>> +fail_irq:
>> +fail_cpufreq_register:
>> +	cpufreq_cooling_unregister(data->cdev);
>> +disable_clk:
>> +err_pclk:
>> +	clk_disable_unprepare(data->pclk);
>> +err_clk:
>> +	clk_disable_unprepare(data->clk);
>> +
>> +	return ret;
>> +}
>> +
>> +static int rockchip_thermal_remove(struct platform_device *pdev)
>> +{
>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>> +
>> +	rockchip_thermal_control(data, false);
>> +
>> +	thermal_zone_device_unregister(data->tz);
>> +	cpufreq_cooling_unregister(data->cdev);
>> +	cpufreq_cooling_unregister(data->cdev);
>> +
> The above call is duplicated.

OK.
>> +	clk_disable_unprepare(data->clk);
>> +	clk_disable_unprepare(data->pclk);
>> +
>> +	return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +static int rockchip_thermal_suspend(struct device *dev)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>> +
>> +	rockchip_thermal_control(data, false);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rockchip_thermal_resume(struct device *dev)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>> +
>> +	rockchip_thermal_initialize(data);
>> +	rockchip_thermal_control(data, true);
>> +
>> +	return 0;
>> +}
> Would you need to manage your clocks too in the suspend resume path
> (data->clk and data->pclk)?
yes.
Usually,it's need disable to save power.
>> +#endif
>> +
>> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
>> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
>> +
>> +static struct platform_driver rockchip_thermal_driver = {
>> +	.driver = {
>> +		   .name = "rockchip-thermal",
>> +		   .owner = THIS_MODULE,
>> +		   .pm = &rockchip_thermal_pm_ops,
>> +		   .of_match_table = of_rockchip_thermal_match,
>> +		   },
>> +	.probe = rockchip_thermal_probe,
>> +	.remove = rockchip_thermal_remove,
>> +};
>> +
>> +module_platform_driver(rockchip_thermal_driver);
>> +
>> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
>> +MODULE_AUTHOR("Rockchip, Inc.");
>> +MODULE_LICENSE("GPL");
> Your file header states GPL version two. Thus I suppose you meant:
> +MODULE_LICENSE("GPL v2");
>
> right?
>
> Check include/linux/module.h for further clarifications.

But I think the  "GPL"  is support for thr GNU Public License v2 or later.
I will fix GPL v2 if I get it wrong.

>> +MODULE_ALIAS("platform:rockchip-thermal");
>> -- 
>> 1.9.1
>>
>>
> BR,
>
> Eduardo Valentin
>
>
>

-- 
Best regards,
Caesar

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-10  1:14                 ` edubezval at gmail.com
  (?)
@ 2014-09-10  7:24                   ` Heiko Stübner
  -1 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-10  7:24 UTC (permalink / raw)
  To: edubezval
  Cc: Zhang Rui, Caesar Wang, LKML, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, Tao Huang, Eddie Cai, Douglas Anderson,
	dtor, Chris Zhong, addy.ke, Dmitry Torokhov, zhaoyifeng

Am Dienstag, 9. September 2014, 21:14:18 schrieb edubezval@gmail.com:
> Hello,
> 
> On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang@intel.com> wrote:
> > On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> >> Hello
> >> 
> >> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko Stübner wrote:
> >> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> >> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> >> > > > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> >> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> >> > > > >> This add the necessary binding documentation for the thermal
> >> > > > >> found on Rockchip SoCs
> >> > > > >> 
> >> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> >> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> >> > > > >> ---
> >> > > > >> 
> >> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> >> > > > >> 
> >> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> >> > > > >> 
> >> > > > >>   create mode 100644
> >> > > > >> 
> >> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> > > > >> 
> >> > > > >> diff --git
> >> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> > > > >> new
> >> > > > >> file
> >> > > > >> mode 100644
> >> > > > >> index 0000000..1ed4d4c
> >> > > > >> --- /dev/null
> >> > > > >> +++
> >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.tx
> >> > > > >> t
> >> > > > >> @@ -0,0 +1,20 @@
> >> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> >> > > > >> +
> >> > > > >> +Required properties:
> >> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> >> > > > >> +- reg: physical base address of the controller and length of
> >> > > > >> memory
> >> > > > >> mapped
> >> > > > >> +       region.
> >> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt
> >> > > > >> specifier
> >> > > > >> format +           depends on the interrupt controller.
> >> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> >> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> >> > > > >> "apb_pclk" for +            the peripheral clock.
> >> > > > > 
> >> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> >> > > > > properties in your driver without declaring them here.
> >> > > > 
> >> > > > frankly,the about are need be declared. but  there are 4 types[0]
> >> > > > for
> >> > > > trip in thermal framework,
> >> > > > there is no force-shut for me. So I want to change it three
> >> > > > additional
> >> > > > properties in [PATCH V4 4/4],
> >> > > > 
> >> > > > 
> >> > > > [0]
> >> > > > {
> >> > > > 
> >> > > >      THERMAL_TRIP_CRITICAL,
> >> > > >      THERMAL_TRIP_HOT,
> >> > > >      THERMAL_TRIP_PASSIVE,
> >> > > >      THERMAL_TRIP_ACTIVE,
> >> > > > 
> >> > > > }
> >> > > 
> >> > > this sounds reasonable to me.
> >> > > 
> >> > > > > But more importantly, please use the generic trip-points for
> >> > > > > this. I
> >> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> >> > > > > trippoint [0] for the additional trip-point you have - thermal
> >> > > > > maintainers, please shout if I'm wrong :-)
> >> > > 
> >> > > what is the difference between a critical trip point and a
> >> > > "forced-shutdown" trip point?
> >> > > Thermal core will do a shutdown in case the critical trip point is
> >> > > triggered.
> >> > 
> >> > The forced-shutdown is where the thermal controller is supposed to also
> >> > do a>> 
> >> Currently, there is no discrimination between hardware configured /
> >> triggered thermal shutdown and software detected / triggered thermal
> >> shutdown. One way to implement it though is to reuse the critical trip
> >> type. Even if you use more than one trip type it is doable, it will
> >> depend on the priorities you give to software triggered and hardware
> >> triggered.
> >> 
> >> > shutdown in hardware. As you said the thermal core will also shutdown
> >> > at the critical trip point, I guess we could map Caesar's value like
> >> > 
> >> > trip-point          tsadc
> >> > critical            forced-shutdown (the 120 degrees in patch 4)
> >> > 
> >> > hot                 critical (the 100 degrees)
> >> > ...
> >> 
> >> In the case we are planing to expand the trip type range, adding one
> >> specific to hardware configurable shutdown makes sense to me too.
> > 
> > hmmm, why? you don't want an orderly shutdown? I still do not understand
> > why we need a hardware shutdown trip point.
> > Say, if we expect the system to be shutdown at 100C, I don't think we
> > have a chance to trigger the hardware shutdown trip point.
> > Further more, if my understanding is right, thermal core won't do
> > anything for the hardware shutdown trip point because the system will be
> > shutdown automatically, right? If this is true, why bother introducing
> > this to thermal core?
> 
> Some ICs allow configuring the temperature when the shutdown will
> happen. That is, you setup in registers the thermal shutdown
> threshold, and one of the output pin of the IC is wired to, say, the
> processor reset pin. Some other ICs have the threshold hardwired, and
> cannot be configured.
> 
> Those options are a last chance to avoid processors to burn, in case
> software really gets stuck at high temperatures.
> 
> The only thing that the thermal driver would need to worry is the
> configuration step, that is, writing the value to the registers. In
> the case the thermal core would have a specific trip type for such
> case, the core itself would not do anything, except allowing designing
> a thermal zone with hardware shutdown trips. And thus the thermal
> driver would do the configuration.
> 
> 
> Currently, the way I see to implement this is to interpret critical
> trips as the threshold to be configured at the IC registers. That is,
> reusing critical trips as orderly power down and as the hardware
> shutdown threshold.

which was what I also meant to express above [but seemingly failed to do 
properly :-) ].

Critical is specified as "Hardware not reliable", so I'd think it wouldn't 
matter how the hw is shut down (orderly/unorderly) as long as its done.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-10  7:24                   ` Heiko Stübner
  0 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-10  7:24 UTC (permalink / raw)
  To: edubezval
  Cc: Zhang Rui, Caesar Wang, LKML, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, Tao Huang, Eddie Cai, Douglas Anderson,
	dtor, Chris Zhong, addy.ke, Dmitry Torokhov, zhaoyifeng

Am Dienstag, 9. September 2014, 21:14:18 schrieb edubezval@gmail.com:
> Hello,
> 
> On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang@intel.com> wrote:
> > On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> >> Hello
> >> 
> >> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko Stübner wrote:
> >> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> >> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> >> > > > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> >> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> >> > > > >> This add the necessary binding documentation for the thermal
> >> > > > >> found on Rockchip SoCs
> >> > > > >> 
> >> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> >> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> >> > > > >> ---
> >> > > > >> 
> >> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> >> > > > >> 
> >> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> >> > > > >> 
> >> > > > >>   create mode 100644
> >> > > > >> 
> >> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> > > > >> 
> >> > > > >> diff --git
> >> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> > > > >> new
> >> > > > >> file
> >> > > > >> mode 100644
> >> > > > >> index 0000000..1ed4d4c
> >> > > > >> --- /dev/null
> >> > > > >> +++
> >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.tx
> >> > > > >> t
> >> > > > >> @@ -0,0 +1,20 @@
> >> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> >> > > > >> +
> >> > > > >> +Required properties:
> >> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> >> > > > >> +- reg: physical base address of the controller and length of
> >> > > > >> memory
> >> > > > >> mapped
> >> > > > >> +       region.
> >> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt
> >> > > > >> specifier
> >> > > > >> format +           depends on the interrupt controller.
> >> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> >> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> >> > > > >> "apb_pclk" for +            the peripheral clock.
> >> > > > > 
> >> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> >> > > > > properties in your driver without declaring them here.
> >> > > > 
> >> > > > frankly,the about are need be declared. but  there are 4 types[0]
> >> > > > for
> >> > > > trip in thermal framework,
> >> > > > there is no force-shut for me. So I want to change it three
> >> > > > additional
> >> > > > properties in [PATCH V4 4/4],
> >> > > > 
> >> > > > 
> >> > > > [0]
> >> > > > {
> >> > > > 
> >> > > >      THERMAL_TRIP_CRITICAL,
> >> > > >      THERMAL_TRIP_HOT,
> >> > > >      THERMAL_TRIP_PASSIVE,
> >> > > >      THERMAL_TRIP_ACTIVE,
> >> > > > 
> >> > > > }
> >> > > 
> >> > > this sounds reasonable to me.
> >> > > 
> >> > > > > But more importantly, please use the generic trip-points for
> >> > > > > this. I
> >> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> >> > > > > trippoint [0] for the additional trip-point you have - thermal
> >> > > > > maintainers, please shout if I'm wrong :-)
> >> > > 
> >> > > what is the difference between a critical trip point and a
> >> > > "forced-shutdown" trip point?
> >> > > Thermal core will do a shutdown in case the critical trip point is
> >> > > triggered.
> >> > 
> >> > The forced-shutdown is where the thermal controller is supposed to also
> >> > do a>> 
> >> Currently, there is no discrimination between hardware configured /
> >> triggered thermal shutdown and software detected / triggered thermal
> >> shutdown. One way to implement it though is to reuse the critical trip
> >> type. Even if you use more than one trip type it is doable, it will
> >> depend on the priorities you give to software triggered and hardware
> >> triggered.
> >> 
> >> > shutdown in hardware. As you said the thermal core will also shutdown
> >> > at the critical trip point, I guess we could map Caesar's value like
> >> > 
> >> > trip-point          tsadc
> >> > critical            forced-shutdown (the 120 degrees in patch 4)
> >> > 
> >> > hot                 critical (the 100 degrees)
> >> > ...
> >> 
> >> In the case we are planing to expand the trip type range, adding one
> >> specific to hardware configurable shutdown makes sense to me too.
> > 
> > hmmm, why? you don't want an orderly shutdown? I still do not understand
> > why we need a hardware shutdown trip point.
> > Say, if we expect the system to be shutdown at 100C, I don't think we
> > have a chance to trigger the hardware shutdown trip point.
> > Further more, if my understanding is right, thermal core won't do
> > anything for the hardware shutdown trip point because the system will be
> > shutdown automatically, right? If this is true, why bother introducing
> > this to thermal core?
> 
> Some ICs allow configuring the temperature when the shutdown will
> happen. That is, you setup in registers the thermal shutdown
> threshold, and one of the output pin of the IC is wired to, say, the
> processor reset pin. Some other ICs have the threshold hardwired, and
> cannot be configured.
> 
> Those options are a last chance to avoid processors to burn, in case
> software really gets stuck at high temperatures.
> 
> The only thing that the thermal driver would need to worry is the
> configuration step, that is, writing the value to the registers. In
> the case the thermal core would have a specific trip type for such
> case, the core itself would not do anything, except allowing designing
> a thermal zone with hardware shutdown trips. And thus the thermal
> driver would do the configuration.
> 
> 
> Currently, the way I see to implement this is to interpret critical
> trips as the threshold to be configured at the IC registers. That is,
> reusing critical trips as orderly power down and as the hardware
> shutdown threshold.

which was what I also meant to express above [but seemingly failed to do 
properly :-) ].

Critical is specified as "Hardware not reliable", so I'd think it wouldn't 
matter how the hw is shut down (orderly/unorderly) as long as its done.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-10  7:24                   ` Heiko Stübner
  0 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-10  7:24 UTC (permalink / raw)
  To: linux-arm-kernel

Am Dienstag, 9. September 2014, 21:14:18 schrieb edubezval at gmail.com:
> Hello,
> 
> On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang@intel.com> wrote:
> > On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> >> Hello
> >> 
> >> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko St?bner wrote:
> >> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> >> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> >> > > > ? 2014?09?03? 16:07, Heiko St?bner ??:
> >> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> >> > > > >> This add the necessary binding documentation for the thermal
> >> > > > >> found on Rockchip SoCs
> >> > > > >> 
> >> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> >> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> >> > > > >> ---
> >> > > > >> 
> >> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> >> > > > >> 
> >> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> >> > > > >> 
> >> > > > >>   create mode 100644
> >> > > > >> 
> >> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> > > > >> 
> >> > > > >> diff --git
> >> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> >> > > > >> new
> >> > > > >> file
> >> > > > >> mode 100644
> >> > > > >> index 0000000..1ed4d4c
> >> > > > >> --- /dev/null
> >> > > > >> +++
> >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.tx
> >> > > > >> t
> >> > > > >> @@ -0,0 +1,20 @@
> >> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> >> > > > >> +
> >> > > > >> +Required properties:
> >> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> >> > > > >> +- reg: physical base address of the controller and length of
> >> > > > >> memory
> >> > > > >> mapped
> >> > > > >> +       region.
> >> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt
> >> > > > >> specifier
> >> > > > >> format +           depends on the interrupt controller.
> >> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> >> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> >> > > > >> "apb_pclk" for +            the peripheral clock.
> >> > > > > 
> >> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> >> > > > > properties in your driver without declaring them here.
> >> > > > 
> >> > > > frankly,the about are need be declared. but  there are 4 types[0]
> >> > > > for
> >> > > > trip in thermal framework,
> >> > > > there is no force-shut for me. So I want to change it three
> >> > > > additional
> >> > > > properties in [PATCH V4 4/4],
> >> > > > 
> >> > > > 
> >> > > > [0]
> >> > > > {
> >> > > > 
> >> > > >      THERMAL_TRIP_CRITICAL,
> >> > > >      THERMAL_TRIP_HOT,
> >> > > >      THERMAL_TRIP_PASSIVE,
> >> > > >      THERMAL_TRIP_ACTIVE,
> >> > > > 
> >> > > > }
> >> > > 
> >> > > this sounds reasonable to me.
> >> > > 
> >> > > > > But more importantly, please use the generic trip-points for
> >> > > > > this. I
> >> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> >> > > > > trippoint [0] for the additional trip-point you have - thermal
> >> > > > > maintainers, please shout if I'm wrong :-)
> >> > > 
> >> > > what is the difference between a critical trip point and a
> >> > > "forced-shutdown" trip point?
> >> > > Thermal core will do a shutdown in case the critical trip point is
> >> > > triggered.
> >> > 
> >> > The forced-shutdown is where the thermal controller is supposed to also
> >> > do a>> 
> >> Currently, there is no discrimination between hardware configured /
> >> triggered thermal shutdown and software detected / triggered thermal
> >> shutdown. One way to implement it though is to reuse the critical trip
> >> type. Even if you use more than one trip type it is doable, it will
> >> depend on the priorities you give to software triggered and hardware
> >> triggered.
> >> 
> >> > shutdown in hardware. As you said the thermal core will also shutdown
> >> > at the critical trip point, I guess we could map Caesar's value like
> >> > 
> >> > trip-point          tsadc
> >> > critical            forced-shutdown (the 120 degrees in patch 4)
> >> > 
> >> > hot                 critical (the 100 degrees)
> >> > ...
> >> 
> >> In the case we are planing to expand the trip type range, adding one
> >> specific to hardware configurable shutdown makes sense to me too.
> > 
> > hmmm, why? you don't want an orderly shutdown? I still do not understand
> > why we need a hardware shutdown trip point.
> > Say, if we expect the system to be shutdown at 100C, I don't think we
> > have a chance to trigger the hardware shutdown trip point.
> > Further more, if my understanding is right, thermal core won't do
> > anything for the hardware shutdown trip point because the system will be
> > shutdown automatically, right? If this is true, why bother introducing
> > this to thermal core?
> 
> Some ICs allow configuring the temperature when the shutdown will
> happen. That is, you setup in registers the thermal shutdown
> threshold, and one of the output pin of the IC is wired to, say, the
> processor reset pin. Some other ICs have the threshold hardwired, and
> cannot be configured.
> 
> Those options are a last chance to avoid processors to burn, in case
> software really gets stuck at high temperatures.
> 
> The only thing that the thermal driver would need to worry is the
> configuration step, that is, writing the value to the registers. In
> the case the thermal core would have a specific trip type for such
> case, the core itself would not do anything, except allowing designing
> a thermal zone with hardware shutdown trips. And thus the thermal
> driver would do the configuration.
> 
> 
> Currently, the way I see to implement this is to interpret critical
> trips as the threshold to be configured at the IC registers. That is,
> reusing critical trips as orderly power down and as the hardware
> shutdown threshold.

which was what I also meant to express above [but seemingly failed to do 
properly :-) ].

Critical is specified as "Hardware not reliable", so I'd think it wouldn't 
matter how the hw is shut down (orderly/unorderly) as long as its done.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 1/4] thermal: rockchip: add driver for thermal
  2014-09-10  4:39       ` Caesar Wang
@ 2014-09-10 12:46         ` Eduardo Valentin
  -1 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-09-10 12:46 UTC (permalink / raw)
  To: Caesar Wang
  Cc: heiko, rui.zhang, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov, zhaoyifeng

Hello Caesar,

On Wed, Sep 10, 2014 at 12:39:07PM +0800, Caesar Wang wrote:
> Dear Eduardo,
> 
> I'm  sorry for it.
> I just received this message.Maybe my mailbox has a problem.


No problems. You can take your time.

> 
> Thank you for your comments.
> 
> 在 2014年08月31日 04:09, Eduardo Valentin 写道:
> > Hello Ceasar,
> >
> > On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
> >> Thermal is TS-ADC Controller module supports
> >> user-defined mode and automatic mode.
> >>
> >> User-defined mode refers,TSADC all the control signals entirely by
> >> software writing to register for direct control.
> >>
> >> Automaic mode refers to the module automatically poll TSADC output,
> >> and the results were checked.If you find that the temperature High
> >> in a period of time,an interrupt is generated to the processor
> >> down-measures taken;if the temperature over a period of time High,
> >> the resulting TSHUT gave CRU module,let it reset the entire chip,
> >> or via GPIO give PMIC.
> >>
> >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>

I forgot to ask, is zhaoyifeng the correct name or is it a nickname? 

> >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> >> ---
> >>   drivers/thermal/Kconfig            |   9 +
> >>   drivers/thermal/Makefile           |   1 +
> >>   drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
> >>   3 files changed, 679 insertions(+)
> >>   create mode 100644 drivers/thermal/rockchip_thermal.c
> >>
> >> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> >> index f9a1386..a00aa1e 100644
> >> --- a/drivers/thermal/Kconfig
> >> +++ b/drivers/thermal/Kconfig
> >> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
> >>   	  Enable this to plug the SPEAr thermal sensor driver into the Linux
> >>   	  thermal framework.
> >>   
> >> +config ROCKCHIP_THERMAL
> >> +	tristate "Rockchip thermal driver"
> >> +	depends on ARCH_ROCKCHIP
> >> +	help
> >> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
> >> +	  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 RCAR_THERMAL
> >>   	tristate "Renesas R-Car thermal driver"
> >>   	depends on ARCH_SHMOBILE || COMPILE_TEST
> >> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> >> index de0636a..b48b817 100644
> >> --- a/drivers/thermal/Makefile
> >> +++ b/drivers/thermal/Makefile
> >> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
> >>   
> >>   # platform thermal drivers
> >>   obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
> >> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
> >>   obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
> >>   obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
> >>   obj-y				+= samsung/
> >> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
> >> new file mode 100644
> >> index 0000000..011f387
> >> --- /dev/null
> >> +++ b/drivers/thermal/rockchip_thermal.c
> >> @@ -0,0 +1,669 @@
> >> +/*
> >> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
> >> + *
> >> + * 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/clk.h>
> >> +#include <linux/io.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/module.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/of_irq.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/regulator/consumer.h>
> >> +#include <linux/cpu_cooling.h>
> >> +#include "thermal_core.h"
> > Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
> > sufficient?
> >
> 
> yes, I will use linux/thermal.h.
> >> +
> >> +enum rockchip_thermal_trip {
> >> +	ROCKCHIP_TRIP_PASSIVE,
> >> +	ROCKCHIP_TRIP_CRITICAL,
> >> +	ROCKCHIP_TRIP_NUM,
> >> +};
> >> +
> > Why do you need your own trip types?
> >
> >> +struct rockchip_thermal_data {
> >> +	const struct rockchip_tsadc_platform_data *pdata;
> >> +	struct thermal_zone_device *tz;
> >> +	struct thermal_cooling_device *cdev;
> >> +	enum thermal_device_mode mode;
> >> +	void __iomem *regs;
> >> +
> >> +	signed long temp_passive;
> >> +	signed long temp_critical;
> >> +	signed long temp_force_shut;
> >> +	signed long alarm_temp;
> >> +	signed long last_temp;
> >> +	bool irq_enabled;
> >> +	int irq;
> >> +	struct clk *clk;
> >> +	struct clk *pclk;
> >> +};
> >> +
> >> +struct rockchip_tsadc_platform_data {
> >> +	u8 irq_en;
> >> +	signed long temp_passive;
> >> +	signed long temp_critical;
> >> +	signed long temp_force_shut;
> >> +	int passive_delay;
> >> +	int polling_delay;
> >> +
> >> +	int (*irq_handle)(void __iomem *reg);
> >> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
> >> +	int (*control)(void __iomem *reg, bool on);
> >> +	u32 (*code_to_temp)(int temp);
> >> +	u32 (*temp_to_code)(int temp);
> >> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
> >> +};
> >> +
> >> +/*TSADC V2 Sensor info define:*/
> >> +#define TSADCV2_AUTO_CON			0x04
> >> +#define TSADCV2_INT_EN				0x08
> >> +#define TSADCV2_INT_PD				0x0c
> >> +#define TSADCV2_DATA1				0x24
> >> +#define TSADCV2_COMP1_INT			0x34
> >> +#define TSADCV2_COMP1_SHUT			0x44
> >> +#define TSADCV2_AUTO_PERIOD			0x68
> >> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
> >> +
> >> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
> >> +#define TSADCV2_AUTO_EN				(1 << 0)
> >> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
> >> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
> >> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
> >> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
> >> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
> >> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
> >> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
> >> +
> > The above bits can be defined with BIT() macro, right?
> 
> Yes. The Bit() will be more resonable..
> >   Something like:
> > +#define TSADCV2_INT_SRC1_STATUS			BIT(1)
> >
> >
> >> +#define TSADCV2_DATA_MASK			0xfff
> >> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
> >> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
> >> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
> >> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
> >> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
> >> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
> >> +
> >> +struct tsadc_table {
> >> +	int code;
> >> +	int temp;
> >> +};
> >> +
> >> +static const struct tsadc_table v2_code_table[] = {
> >> +	{TSADCV2_DATA_MASK, -40},
> >> +	{3800, -40},
> >> +	{3792, -35},
> >> +	{3783, -30},
> >> +	{3774, -25},
> >> +	{3765, -20},
> >> +	{3756, -15},
> >> +	{3747, -10},
> >> +	{3737, -5},
> >> +	{3728, 0},
> >> +	{3718, 5},
> >> +	{3708, 10},
> >> +	{3698, 15},
> >> +	{3688, 20},
> >> +	{3678, 25},
> >> +	{3667, 30},
> >> +	{3656, 35},
> >> +	{3645, 40},
> >> +	{3634, 45},
> >> +	{3623, 50},
> >> +	{3611, 55},
> >> +	{3600, 60},
> >> +	{3588, 65},
> >> +	{3575, 70},
> >> +	{3563, 75},
> >> +	{3550, 80},
> >> +	{3537, 85},
> >> +	{3524, 90},
> >> +	{3510, 95},
> >> +	{3496, 100},
> >> +	{3482, 105},
> >> +	{3467, 110},
> >> +	{3452, 115},
> >> +	{3437, 120},
> >> +	{3421, 125},
> >> +	{0, 125},
> >> +};
> >> +
> >> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
> >> +{
> >> +	u32 val;
> >> +
> >> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
> >> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
> > Why do you need to clear bit 8? Why hardcoded?
> 
> The bit 8 set 0 to clear the interrupt.
> 

Would it make sense to create a macro for this?

> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static u32 rk_tsadcv2_temp_to_code(int temp)
> >> +{
> >> +	int i;
> >> +
> >> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
> >> +		if (temp <= v2_code_table[i].temp && temp >
> >> +		    v2_code_table[i - 1].temp)
> >> +			return v2_code_table[i].code;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static u32 rk_tsadcv2_code_to_temp(int code)
> >> +{
> >> +	int i;
> >> +
> >> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
> >> +		if (code <= v2_code_table[i].code && code >
> >> +		    v2_code_table[i + 1].code){
> >> +			return v2_code_table[i].temp;
> >> +		}
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> > I know the table is not something too big, but considering it is ordered
> > by either ADC value code or by temp, at least one of the above searching function
> > may be more efficient, right?
> Yes, use the point will be more efficient.
> >> +
> >> +static int rk_tsadcv2_initialize(void __iomem *regs,
> >> +				 signed long temp_force_shut)
> >> +{
> >> +	int shutdown_value;
> >> +
> >> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
> >> +	/* Enable measurements at ~ 10 Hz */
> > Does it leave the sampling clock at 10Hz?
> yes.

ok


> > Is this clock exposed via
> > clock framework?
> 
> The clock is divided by data->clk.

ok

> >
> >> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
> >> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
> >> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
> >> +		       TSADCV2_AUTO_PERIOD_HT);
> >> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
> >> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
> >> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
> >> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
> >> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
> >> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
> >> +		       TSADCV2_INT_EN);
> >> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
> >> +		       TSADCV2_AUTO_CON);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
> >> +{
> >> +	u32 val;
> >> +
> >> +	if (on) {
> >> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
> >> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
> >> +	} else {
> >> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
> >> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
> >> +			       regs + TSADCV2_AUTO_CON);
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
> >> +{
> >> +	int alarm_value;
> >> +
> >> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
> >> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
> >> +}
> >> +
> >> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
> >> +	.irq_en = 1,
> >> +	.temp_passive = 85000,
> >> +	.temp_critical = 100000,
> >> +	.temp_force_shut = 120000,
> >> +	.passive_delay = 2000,
> >> +	.polling_delay = 1000,
> >> +	.irq_handle = rk_tsadcv2_irq_handle,
> >> +	.initialize = rk_tsadcv2_initialize,
> >> +	.control = rk_tsadcv2_control,
> >> +	.code_to_temp = rk_tsadcv2_code_to_temp,
> >> +	.temp_to_code = rk_tsadcv2_temp_to_code,
> >> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
> >> +};
> > shall the above struct be also static?
> OK.
> >> +
> >> +static const struct of_device_id of_rockchip_thermal_match[] = {
> >> +	{
> >> +		.compatible = "rockchip,rk3288-tsadc",
> >> +		.data = (void *)&rk3288_tsadc_data,
> >> +	},
> >> +	{ /* end */ },
> >> +};
> >> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
> >> +
> >> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
> >> +				    signed long alarm_temp)
> >> +{
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +
> >> +	data->alarm_temp = alarm_temp;
> >> +	if (p_tsadc_data->set_alarm_temp)
> >> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
> >> +}
> >> +
> >> +static int rockchip_get_temp(struct thermal_zone_device *tz,
> >> +			     unsigned long *temp)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +	u32 val;
> >> +
> >> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
> >> +	*temp = p_tsadc_data->code_to_temp(val);
> >> +
> >> +	/* Update alarm value to next higher trip point */
> >> +	if (data->alarm_temp == data->temp_passive && *temp >=
> >> +	    data->temp_passive)
> >> +		rockchip_set_alarm_temp(data, data->temp_critical);
> >> +
> >> +	if (data->alarm_temp == data->temp_critical && *temp <
> >> +	    data->temp_passive) {
> >> +		rockchip_set_alarm_temp(data, data->temp_passive);
> >> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
> >> +			data->alarm_temp / 1000);
> >> +	}
> >> +
> >> +	if (*temp != data->last_temp) {
> >> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
> >> +		data->last_temp = *temp;
> >> +	}
> >> +
> >> +	/* Reenable alarm IRQ if temperature below alarm temperature */
> >> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
> >> +		data->irq_enabled = true;
> >> +		enable_irq(data->irq);
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
> >> +{
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +
> >> +	if (p_tsadc_data->initialize)
> >> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
> >> +	rockchip_set_alarm_temp(data, data->temp_passive);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
> >> +				     bool on)
> >> +{
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +
> >> +	if (p_tsadc_data->control)
> >> +		p_tsadc_data->control(data->regs, on);
> >> +
> >> +	if (on) {
> >> +		data->irq_enabled = true;
> >> +		data->mode = THERMAL_DEVICE_ENABLED;
> >> +	} else {
> >> +		data->irq_enabled = false;
> >> +		data->mode = THERMAL_DEVICE_DISABLED;
> >> +	}
> >> +}
> >> +
> >> +static int rockchip_get_mode(struct thermal_zone_device *tz,
> >> +			     enum thermal_device_mode *mode)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +
> >> +	*mode = data->mode;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_set_mode(struct thermal_zone_device *tz,
> >> +			     enum thermal_device_mode mode)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +
> >> +	if (mode == THERMAL_DEVICE_ENABLED) {
> >> +		tz->polling_delay = p_tsadc_data->polling_delay;
> >> +		tz->passive_delay = p_tsadc_data->passive_delay;
> >> +		if (!data->irq_enabled) {
> >> +			data->irq_enabled = true;
> >> +			enable_irq(data->irq);
> >> +		}
> >> +	} else {
> >> +		tz->polling_delay = 0;
> >> +		tz->passive_delay = 0;
> >> +		if (data->irq_enabled) {
> >> +			disable_irq(data->irq);
> >> +			data->irq_enabled = false;
> >> +		}
> >> +	}
> >> +
> >> +	data->mode = mode;
> >> +	thermal_zone_device_update(tz);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
> >> +				  enum thermal_trip_type *type)
> >> +{
> >> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
> >> +		 THERMAL_TRIP_CRITICAL;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
> >> +				  unsigned long *temp)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +
> >> +	*temp = data->temp_critical;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
> >> +				  unsigned long *temp)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +
> >> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
> >> +		 data->temp_critical;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
> >> +				  unsigned long temp)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +
> >> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
> >> +		return -EPERM;
> >> +
> >> +	data->temp_passive = temp;
> >> +	rockchip_set_alarm_temp(data, temp);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_bind(struct thermal_zone_device *tz,
> >> +			 struct thermal_cooling_device *cdev)
> >> +{
> >> +	int ret;
> >> +
> >> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
> >> +					       THERMAL_NO_LIMIT,
> >> +					       THERMAL_NO_LIMIT);
> >> +	if (ret) {
> >> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> >> +			tz->type, cdev->type, ret);
> >> +		return ret;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_unbind(struct thermal_zone_device *tz,
> >> +			   struct thermal_cooling_device *cdev)
> >> +{
> >> +	int ret;
> >> +
> >> +	ret = thermal_zone_unbind_cooling_device(tz,
> >> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
> >> +	if (ret) {
> >> +		dev_err(&tz->device,
> >> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
> >> +			cdev->type, ret);
> >> +		return ret;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> > The method of binding and unbinding used above requires you to check if
> > you are binding to the right cdev. If in your system you register more
> > than one cdev, say someone loads the power supply core, which in turns
> > register a cooling device for charging, your thermal zone will bind it
> > to TRIP_PASSIVE. It will happen to any cooling device that eventually
> > gets registered to the thermal framework. Is that the desired outcome?
> 
> Yes,I will use the generic trip points in the dts and fix it in the 
> thermal driver.

great

> > If not, you may want to compare the paramenter cdev to your data->cdev.
> >
> >> +
> >> +static struct thermal_zone_device_ops rockchip_tz_ops = {
> >> +	.bind = rockchip_bind,
> >> +	.unbind = rockchip_unbind,
> >> +	.get_temp = rockchip_get_temp,
> >> +	.get_mode = rockchip_get_mode,
> >> +	.set_mode = rockchip_set_mode,
> >> +	.get_trip_type = rockchip_get_trip_type,
> >> +	.get_trip_temp = rockchip_get_trip_temp,
> >> +	.get_crit_temp = rockchip_get_crit_temp,
> >> +	.set_trip_temp = rockchip_set_trip_temp,
> >> +};
> >> +
> >> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
> >> +{
> >> +	struct rockchip_thermal_data *data = data;
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +
> >> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
> >> +		data->alarm_temp / 1000);
> >> +
> >> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
> >> +		p_tsadc_data->irq_handle(data->regs);
> >> +
> >> +	thermal_zone_device_update(data->tz);
> >> +
> >> +	return IRQ_HANDLED;
> >> +}
> >> +
> >> +static int rockchip_thermal_probe(struct platform_device *pdev)
> >> +{
> >> +	struct rockchip_thermal_data *data;
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
> >> +	struct cpumask clip_cpus;
> >> +	struct resource *res;
> >> +	const struct of_device_id *match;
> >> +	int ret, temp;
> >> +
> >> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
> >> +			    GFP_KERNEL);
> >> +	if (!data)
> >> +		return -ENOMEM;
> >> +
> >> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
> >> +	if (IS_ERR(data->regs)) {
> >> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
> >> +			data->regs);
> >> +		return PTR_ERR(data->regs);
> >> +	}
> >> +
> >> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
> >> +	if (!match)
> >> +		return -ENXIO;
> >> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
> >> +	if (!data->pdata)
> >> +		return -EINVAL;
> >> +	p_tsadc_data = data->pdata;
> >> +
> >> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
> >> +	if (IS_ERR(data->clk)) {
> >> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
> >> +		return PTR_ERR(data->clk);
> >> +	}
> >> +
> >> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
> >> +	if (IS_ERR(data->pclk)) {
> >> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
> >> +		return PTR_ERR(data->pclk);
> >> +	}
> >> +
> >> +	/*
> >> +	* Use a default of 10KHz for the converter clock.
> >> +	* This may become user-configurable in the future.
> >> +	*/
> >> +	ret = clk_set_rate(data->clk, 10000);
> >> +	if (ret < 0) {
> >> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
> >> +		return ret;
> >> +	}
> >> +
> >> +	ret = clk_prepare_enable(data->clk);
> >> +	if (ret < 0) {
> >> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
> >> +		goto err_clk;
> >> +	}
> >> +
> >> +	ret = clk_prepare_enable(data->pclk);
> >> +	if (ret < 0) {
> >> +		dev_err(&pdev->dev, "failed to enable pclk\n");
> >> +		goto err_pclk;
> >> +	}
> >> +
> >> +	platform_set_drvdata(pdev, data);
> >> +
> >> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
> >> +		dev_warn(&pdev->dev,
> >> +			 "Missing default passive temp property in the DT.\n");
> >> +		data->temp_passive = p_tsadc_data->temp_passive;
> >> +	} else {
> >> +		data->temp_passive = temp;
> >> +	}
> >> +
> >> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
> >> +		dev_warn(&pdev->dev,
> >> +			 "Missing default critical temp property in the DT.\n");
> >> +		data->temp_critical = p_tsadc_data->temp_critical;
> >> +	} else {
> >> +		data->temp_critical = temp;
> >> +	}
> >> +
> >> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
> >> +		dev_warn(&pdev->dev,
> >> +			 "Missing default force shut down temp property in the DT.\n");
> >> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
> >> +	} else {
> >> +		data->temp_force_shut = temp;
> >> +	}
> >> +
> >> +	cpumask_set_cpu(0, &clip_cpus);
> >> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
> >> +	if (IS_ERR(data->cdev)) {
> >> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
> >> +		goto disable_clk;
> >> +	}
> >> +
> >> +	data->tz = thermal_zone_device_register("rockchip_thermal",
> >> +						ROCKCHIP_TRIP_NUM,
> >> +						0, data,
> >> +						&rockchip_tz_ops, NULL,
> >> +						p_tsadc_data->passive_delay,
> >> +						p_tsadc_data->polling_delay);
> >> +
> >> +	if (IS_ERR(data->tz)) {
> >> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
> >> +		goto fail_cpufreq_register;
> >> +	}
> >> +
> >> +	if (p_tsadc_data->irq_en) {
> >> +		data->irq = platform_get_irq(pdev, 0);
> >> +		if (data->irq < 0) {
> >> +			dev_err(&pdev->dev, "no irq resource?\n");
> >> +			goto fail_irq;
> >> +		}
> >> +
> >> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
> >> +				rockchip_thermal_alarm_irq_thread,
> >> +				IRQF_ONESHOT, "rockchip_thermal", data);
> >> +		if (ret < 0) {
> >> +			dev_err(&pdev->dev,
> >> +				"failed to request tsadc irq: %d\n", ret);
> >> +			goto fail_thermal_unregister;
> >> +		}
> >> +	}
> >> +
> >> +	rockchip_thermal_initialize(data);
> >> +	rockchip_thermal_control(data, true);
> >> +
> >> +	return 0;
> >> +
> >> +fail_thermal_unregister:
> >> +	thermal_zone_device_unregister(data->tz);
> >> +fail_irq:
> >> +fail_cpufreq_register:
> >> +	cpufreq_cooling_unregister(data->cdev);
> >> +disable_clk:
> >> +err_pclk:
> >> +	clk_disable_unprepare(data->pclk);
> >> +err_clk:
> >> +	clk_disable_unprepare(data->clk);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static int rockchip_thermal_remove(struct platform_device *pdev)
> >> +{
> >> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> >> +
> >> +	rockchip_thermal_control(data, false);
> >> +
> >> +	thermal_zone_device_unregister(data->tz);
> >> +	cpufreq_cooling_unregister(data->cdev);
> >> +	cpufreq_cooling_unregister(data->cdev);
> >> +
> > The above call is duplicated.
> 
> OK.
> >> +	clk_disable_unprepare(data->clk);
> >> +	clk_disable_unprepare(data->pclk);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +#ifdef CONFIG_PM_SLEEP
> >> +static int rockchip_thermal_suspend(struct device *dev)
> >> +{
> >> +	struct platform_device *pdev = to_platform_device(dev);
> >> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> >> +
> >> +	rockchip_thermal_control(data, false);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_thermal_resume(struct device *dev)
> >> +{
> >> +	struct platform_device *pdev = to_platform_device(dev);
> >> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> >> +
> >> +	rockchip_thermal_initialize(data);
> >> +	rockchip_thermal_control(data, true);
> >> +
> >> +	return 0;
> >> +}
> > Would you need to manage your clocks too in the suspend resume path
> > (data->clk and data->pclk)?
> yes.
> Usually,it's need disable to save power.

Yes, that's my point. Please consider handling clocks to improve power
savings.

> >> +#endif
> >> +
> >> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
> >> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
> >> +
> >> +static struct platform_driver rockchip_thermal_driver = {
> >> +	.driver = {
> >> +		   .name = "rockchip-thermal",
> >> +		   .owner = THIS_MODULE,
> >> +		   .pm = &rockchip_thermal_pm_ops,
> >> +		   .of_match_table = of_rockchip_thermal_match,
> >> +		   },
> >> +	.probe = rockchip_thermal_probe,
> >> +	.remove = rockchip_thermal_remove,
> >> +};
> >> +
> >> +module_platform_driver(rockchip_thermal_driver);
> >> +
> >> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
> >> +MODULE_AUTHOR("Rockchip, Inc.");
> >> +MODULE_LICENSE("GPL");
> > Your file header states GPL version two. Thus I suppose you meant:
> > +MODULE_LICENSE("GPL v2");
> >
> > right?
> >
> > Check include/linux/module.h for further clarifications.
> 
> But I think the  "GPL"  is support for thr GNU Public License v2 or later.

Exactly, if you intend to support v3, then it is fine. But your code
header states only V2.

> I will fix GPL v2 if I get it wrong.

If your license is GPLv2 only as mentioned in your header, please use 'GPL
v2' tag.

Cheers,

> 
> >> +MODULE_ALIAS("platform:rockchip-thermal");
> >> -- 
> >> 1.9.1
> >>
> >>
> > BR,
> >
> > Eduardo Valentin
> >
> >
> >
> 
> -- 
> Best regards,
> Caesar
> 
> 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 1/4] thermal: rockchip: add driver for thermal
@ 2014-09-10 12:46         ` Eduardo Valentin
  0 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-09-10 12:46 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Caesar,

On Wed, Sep 10, 2014 at 12:39:07PM +0800, Caesar Wang wrote:
> Dear Eduardo,
> 
> I'm  sorry for it.
> I just received this message.Maybe my mailbox has a problem.


No problems. You can take your time.

> 
> Thank you for your comments.
> 
> ? 2014?08?31? 04:09, Eduardo Valentin ??:
> > Hello Ceasar,
> >
> > On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
> >> Thermal is TS-ADC Controller module supports
> >> user-defined mode and automatic mode.
> >>
> >> User-defined mode refers,TSADC all the control signals entirely by
> >> software writing to register for direct control.
> >>
> >> Automaic mode refers to the module automatically poll TSADC output,
> >> and the results were checked.If you find that the temperature High
> >> in a period of time,an interrupt is generated to the processor
> >> down-measures taken;if the temperature over a period of time High,
> >> the resulting TSHUT gave CRU module,let it reset the entire chip,
> >> or via GPIO give PMIC.
> >>
> >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>

I forgot to ask, is zhaoyifeng the correct name or is it a nickname? 

> >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> >> ---
> >>   drivers/thermal/Kconfig            |   9 +
> >>   drivers/thermal/Makefile           |   1 +
> >>   drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
> >>   3 files changed, 679 insertions(+)
> >>   create mode 100644 drivers/thermal/rockchip_thermal.c
> >>
> >> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> >> index f9a1386..a00aa1e 100644
> >> --- a/drivers/thermal/Kconfig
> >> +++ b/drivers/thermal/Kconfig
> >> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
> >>   	  Enable this to plug the SPEAr thermal sensor driver into the Linux
> >>   	  thermal framework.
> >>   
> >> +config ROCKCHIP_THERMAL
> >> +	tristate "Rockchip thermal driver"
> >> +	depends on ARCH_ROCKCHIP
> >> +	help
> >> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
> >> +	  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 RCAR_THERMAL
> >>   	tristate "Renesas R-Car thermal driver"
> >>   	depends on ARCH_SHMOBILE || COMPILE_TEST
> >> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> >> index de0636a..b48b817 100644
> >> --- a/drivers/thermal/Makefile
> >> +++ b/drivers/thermal/Makefile
> >> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
> >>   
> >>   # platform thermal drivers
> >>   obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
> >> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
> >>   obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
> >>   obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
> >>   obj-y				+= samsung/
> >> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
> >> new file mode 100644
> >> index 0000000..011f387
> >> --- /dev/null
> >> +++ b/drivers/thermal/rockchip_thermal.c
> >> @@ -0,0 +1,669 @@
> >> +/*
> >> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
> >> + *
> >> + * 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/clk.h>
> >> +#include <linux/io.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/module.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/of_irq.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/regulator/consumer.h>
> >> +#include <linux/cpu_cooling.h>
> >> +#include "thermal_core.h"
> > Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
> > sufficient?
> >
> 
> yes, I will use linux/thermal.h.
> >> +
> >> +enum rockchip_thermal_trip {
> >> +	ROCKCHIP_TRIP_PASSIVE,
> >> +	ROCKCHIP_TRIP_CRITICAL,
> >> +	ROCKCHIP_TRIP_NUM,
> >> +};
> >> +
> > Why do you need your own trip types?
> >
> >> +struct rockchip_thermal_data {
> >> +	const struct rockchip_tsadc_platform_data *pdata;
> >> +	struct thermal_zone_device *tz;
> >> +	struct thermal_cooling_device *cdev;
> >> +	enum thermal_device_mode mode;
> >> +	void __iomem *regs;
> >> +
> >> +	signed long temp_passive;
> >> +	signed long temp_critical;
> >> +	signed long temp_force_shut;
> >> +	signed long alarm_temp;
> >> +	signed long last_temp;
> >> +	bool irq_enabled;
> >> +	int irq;
> >> +	struct clk *clk;
> >> +	struct clk *pclk;
> >> +};
> >> +
> >> +struct rockchip_tsadc_platform_data {
> >> +	u8 irq_en;
> >> +	signed long temp_passive;
> >> +	signed long temp_critical;
> >> +	signed long temp_force_shut;
> >> +	int passive_delay;
> >> +	int polling_delay;
> >> +
> >> +	int (*irq_handle)(void __iomem *reg);
> >> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
> >> +	int (*control)(void __iomem *reg, bool on);
> >> +	u32 (*code_to_temp)(int temp);
> >> +	u32 (*temp_to_code)(int temp);
> >> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
> >> +};
> >> +
> >> +/*TSADC V2 Sensor info define:*/
> >> +#define TSADCV2_AUTO_CON			0x04
> >> +#define TSADCV2_INT_EN				0x08
> >> +#define TSADCV2_INT_PD				0x0c
> >> +#define TSADCV2_DATA1				0x24
> >> +#define TSADCV2_COMP1_INT			0x34
> >> +#define TSADCV2_COMP1_SHUT			0x44
> >> +#define TSADCV2_AUTO_PERIOD			0x68
> >> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
> >> +
> >> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
> >> +#define TSADCV2_AUTO_EN				(1 << 0)
> >> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
> >> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
> >> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
> >> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
> >> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
> >> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
> >> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
> >> +
> > The above bits can be defined with BIT() macro, right?
> 
> Yes. The Bit() will be more resonable..
> >   Something like:
> > +#define TSADCV2_INT_SRC1_STATUS			BIT(1)
> >
> >
> >> +#define TSADCV2_DATA_MASK			0xfff
> >> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
> >> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
> >> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
> >> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
> >> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
> >> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
> >> +
> >> +struct tsadc_table {
> >> +	int code;
> >> +	int temp;
> >> +};
> >> +
> >> +static const struct tsadc_table v2_code_table[] = {
> >> +	{TSADCV2_DATA_MASK, -40},
> >> +	{3800, -40},
> >> +	{3792, -35},
> >> +	{3783, -30},
> >> +	{3774, -25},
> >> +	{3765, -20},
> >> +	{3756, -15},
> >> +	{3747, -10},
> >> +	{3737, -5},
> >> +	{3728, 0},
> >> +	{3718, 5},
> >> +	{3708, 10},
> >> +	{3698, 15},
> >> +	{3688, 20},
> >> +	{3678, 25},
> >> +	{3667, 30},
> >> +	{3656, 35},
> >> +	{3645, 40},
> >> +	{3634, 45},
> >> +	{3623, 50},
> >> +	{3611, 55},
> >> +	{3600, 60},
> >> +	{3588, 65},
> >> +	{3575, 70},
> >> +	{3563, 75},
> >> +	{3550, 80},
> >> +	{3537, 85},
> >> +	{3524, 90},
> >> +	{3510, 95},
> >> +	{3496, 100},
> >> +	{3482, 105},
> >> +	{3467, 110},
> >> +	{3452, 115},
> >> +	{3437, 120},
> >> +	{3421, 125},
> >> +	{0, 125},
> >> +};
> >> +
> >> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
> >> +{
> >> +	u32 val;
> >> +
> >> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
> >> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
> > Why do you need to clear bit 8? Why hardcoded?
> 
> The bit 8 set 0 to clear the interrupt.
> 

Would it make sense to create a macro for this?

> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static u32 rk_tsadcv2_temp_to_code(int temp)
> >> +{
> >> +	int i;
> >> +
> >> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
> >> +		if (temp <= v2_code_table[i].temp && temp >
> >> +		    v2_code_table[i - 1].temp)
> >> +			return v2_code_table[i].code;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static u32 rk_tsadcv2_code_to_temp(int code)
> >> +{
> >> +	int i;
> >> +
> >> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
> >> +		if (code <= v2_code_table[i].code && code >
> >> +		    v2_code_table[i + 1].code){
> >> +			return v2_code_table[i].temp;
> >> +		}
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> > I know the table is not something too big, but considering it is ordered
> > by either ADC value code or by temp, at least one of the above searching function
> > may be more efficient, right?
> Yes, use the point will be more efficient.
> >> +
> >> +static int rk_tsadcv2_initialize(void __iomem *regs,
> >> +				 signed long temp_force_shut)
> >> +{
> >> +	int shutdown_value;
> >> +
> >> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
> >> +	/* Enable measurements at ~ 10 Hz */
> > Does it leave the sampling clock at 10Hz?
> yes.

ok


> > Is this clock exposed via
> > clock framework?
> 
> The clock is divided by data->clk.

ok

> >
> >> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
> >> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
> >> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
> >> +		       TSADCV2_AUTO_PERIOD_HT);
> >> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
> >> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
> >> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
> >> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
> >> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
> >> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
> >> +		       TSADCV2_INT_EN);
> >> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
> >> +		       TSADCV2_AUTO_CON);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
> >> +{
> >> +	u32 val;
> >> +
> >> +	if (on) {
> >> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
> >> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
> >> +	} else {
> >> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
> >> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
> >> +			       regs + TSADCV2_AUTO_CON);
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
> >> +{
> >> +	int alarm_value;
> >> +
> >> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
> >> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
> >> +}
> >> +
> >> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
> >> +	.irq_en = 1,
> >> +	.temp_passive = 85000,
> >> +	.temp_critical = 100000,
> >> +	.temp_force_shut = 120000,
> >> +	.passive_delay = 2000,
> >> +	.polling_delay = 1000,
> >> +	.irq_handle = rk_tsadcv2_irq_handle,
> >> +	.initialize = rk_tsadcv2_initialize,
> >> +	.control = rk_tsadcv2_control,
> >> +	.code_to_temp = rk_tsadcv2_code_to_temp,
> >> +	.temp_to_code = rk_tsadcv2_temp_to_code,
> >> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
> >> +};
> > shall the above struct be also static?
> OK.
> >> +
> >> +static const struct of_device_id of_rockchip_thermal_match[] = {
> >> +	{
> >> +		.compatible = "rockchip,rk3288-tsadc",
> >> +		.data = (void *)&rk3288_tsadc_data,
> >> +	},
> >> +	{ /* end */ },
> >> +};
> >> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
> >> +
> >> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
> >> +				    signed long alarm_temp)
> >> +{
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +
> >> +	data->alarm_temp = alarm_temp;
> >> +	if (p_tsadc_data->set_alarm_temp)
> >> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
> >> +}
> >> +
> >> +static int rockchip_get_temp(struct thermal_zone_device *tz,
> >> +			     unsigned long *temp)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +	u32 val;
> >> +
> >> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
> >> +	*temp = p_tsadc_data->code_to_temp(val);
> >> +
> >> +	/* Update alarm value to next higher trip point */
> >> +	if (data->alarm_temp == data->temp_passive && *temp >=
> >> +	    data->temp_passive)
> >> +		rockchip_set_alarm_temp(data, data->temp_critical);
> >> +
> >> +	if (data->alarm_temp == data->temp_critical && *temp <
> >> +	    data->temp_passive) {
> >> +		rockchip_set_alarm_temp(data, data->temp_passive);
> >> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
> >> +			data->alarm_temp / 1000);
> >> +	}
> >> +
> >> +	if (*temp != data->last_temp) {
> >> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
> >> +		data->last_temp = *temp;
> >> +	}
> >> +
> >> +	/* Reenable alarm IRQ if temperature below alarm temperature */
> >> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
> >> +		data->irq_enabled = true;
> >> +		enable_irq(data->irq);
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
> >> +{
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +
> >> +	if (p_tsadc_data->initialize)
> >> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
> >> +	rockchip_set_alarm_temp(data, data->temp_passive);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
> >> +				     bool on)
> >> +{
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +
> >> +	if (p_tsadc_data->control)
> >> +		p_tsadc_data->control(data->regs, on);
> >> +
> >> +	if (on) {
> >> +		data->irq_enabled = true;
> >> +		data->mode = THERMAL_DEVICE_ENABLED;
> >> +	} else {
> >> +		data->irq_enabled = false;
> >> +		data->mode = THERMAL_DEVICE_DISABLED;
> >> +	}
> >> +}
> >> +
> >> +static int rockchip_get_mode(struct thermal_zone_device *tz,
> >> +			     enum thermal_device_mode *mode)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +
> >> +	*mode = data->mode;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_set_mode(struct thermal_zone_device *tz,
> >> +			     enum thermal_device_mode mode)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +
> >> +	if (mode == THERMAL_DEVICE_ENABLED) {
> >> +		tz->polling_delay = p_tsadc_data->polling_delay;
> >> +		tz->passive_delay = p_tsadc_data->passive_delay;
> >> +		if (!data->irq_enabled) {
> >> +			data->irq_enabled = true;
> >> +			enable_irq(data->irq);
> >> +		}
> >> +	} else {
> >> +		tz->polling_delay = 0;
> >> +		tz->passive_delay = 0;
> >> +		if (data->irq_enabled) {
> >> +			disable_irq(data->irq);
> >> +			data->irq_enabled = false;
> >> +		}
> >> +	}
> >> +
> >> +	data->mode = mode;
> >> +	thermal_zone_device_update(tz);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
> >> +				  enum thermal_trip_type *type)
> >> +{
> >> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
> >> +		 THERMAL_TRIP_CRITICAL;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
> >> +				  unsigned long *temp)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +
> >> +	*temp = data->temp_critical;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
> >> +				  unsigned long *temp)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +
> >> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
> >> +		 data->temp_critical;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
> >> +				  unsigned long temp)
> >> +{
> >> +	struct rockchip_thermal_data *data = tz->devdata;
> >> +
> >> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
> >> +		return -EPERM;
> >> +
> >> +	data->temp_passive = temp;
> >> +	rockchip_set_alarm_temp(data, temp);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_bind(struct thermal_zone_device *tz,
> >> +			 struct thermal_cooling_device *cdev)
> >> +{
> >> +	int ret;
> >> +
> >> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
> >> +					       THERMAL_NO_LIMIT,
> >> +					       THERMAL_NO_LIMIT);
> >> +	if (ret) {
> >> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> >> +			tz->type, cdev->type, ret);
> >> +		return ret;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_unbind(struct thermal_zone_device *tz,
> >> +			   struct thermal_cooling_device *cdev)
> >> +{
> >> +	int ret;
> >> +
> >> +	ret = thermal_zone_unbind_cooling_device(tz,
> >> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
> >> +	if (ret) {
> >> +		dev_err(&tz->device,
> >> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
> >> +			cdev->type, ret);
> >> +		return ret;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> > The method of binding and unbinding used above requires you to check if
> > you are binding to the right cdev. If in your system you register more
> > than one cdev, say someone loads the power supply core, which in turns
> > register a cooling device for charging, your thermal zone will bind it
> > to TRIP_PASSIVE. It will happen to any cooling device that eventually
> > gets registered to the thermal framework. Is that the desired outcome?
> 
> Yes,I will use the generic trip points in the dts and fix it in the 
> thermal driver.

great

> > If not, you may want to compare the paramenter cdev to your data->cdev.
> >
> >> +
> >> +static struct thermal_zone_device_ops rockchip_tz_ops = {
> >> +	.bind = rockchip_bind,
> >> +	.unbind = rockchip_unbind,
> >> +	.get_temp = rockchip_get_temp,
> >> +	.get_mode = rockchip_get_mode,
> >> +	.set_mode = rockchip_set_mode,
> >> +	.get_trip_type = rockchip_get_trip_type,
> >> +	.get_trip_temp = rockchip_get_trip_temp,
> >> +	.get_crit_temp = rockchip_get_crit_temp,
> >> +	.set_trip_temp = rockchip_set_trip_temp,
> >> +};
> >> +
> >> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
> >> +{
> >> +	struct rockchip_thermal_data *data = data;
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
> >> +
> >> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
> >> +		data->alarm_temp / 1000);
> >> +
> >> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
> >> +		p_tsadc_data->irq_handle(data->regs);
> >> +
> >> +	thermal_zone_device_update(data->tz);
> >> +
> >> +	return IRQ_HANDLED;
> >> +}
> >> +
> >> +static int rockchip_thermal_probe(struct platform_device *pdev)
> >> +{
> >> +	struct rockchip_thermal_data *data;
> >> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
> >> +	struct cpumask clip_cpus;
> >> +	struct resource *res;
> >> +	const struct of_device_id *match;
> >> +	int ret, temp;
> >> +
> >> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
> >> +			    GFP_KERNEL);
> >> +	if (!data)
> >> +		return -ENOMEM;
> >> +
> >> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
> >> +	if (IS_ERR(data->regs)) {
> >> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
> >> +			data->regs);
> >> +		return PTR_ERR(data->regs);
> >> +	}
> >> +
> >> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
> >> +	if (!match)
> >> +		return -ENXIO;
> >> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
> >> +	if (!data->pdata)
> >> +		return -EINVAL;
> >> +	p_tsadc_data = data->pdata;
> >> +
> >> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
> >> +	if (IS_ERR(data->clk)) {
> >> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
> >> +		return PTR_ERR(data->clk);
> >> +	}
> >> +
> >> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
> >> +	if (IS_ERR(data->pclk)) {
> >> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
> >> +		return PTR_ERR(data->pclk);
> >> +	}
> >> +
> >> +	/*
> >> +	* Use a default of 10KHz for the converter clock.
> >> +	* This may become user-configurable in the future.
> >> +	*/
> >> +	ret = clk_set_rate(data->clk, 10000);
> >> +	if (ret < 0) {
> >> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
> >> +		return ret;
> >> +	}
> >> +
> >> +	ret = clk_prepare_enable(data->clk);
> >> +	if (ret < 0) {
> >> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
> >> +		goto err_clk;
> >> +	}
> >> +
> >> +	ret = clk_prepare_enable(data->pclk);
> >> +	if (ret < 0) {
> >> +		dev_err(&pdev->dev, "failed to enable pclk\n");
> >> +		goto err_pclk;
> >> +	}
> >> +
> >> +	platform_set_drvdata(pdev, data);
> >> +
> >> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
> >> +		dev_warn(&pdev->dev,
> >> +			 "Missing default passive temp property in the DT.\n");
> >> +		data->temp_passive = p_tsadc_data->temp_passive;
> >> +	} else {
> >> +		data->temp_passive = temp;
> >> +	}
> >> +
> >> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
> >> +		dev_warn(&pdev->dev,
> >> +			 "Missing default critical temp property in the DT.\n");
> >> +		data->temp_critical = p_tsadc_data->temp_critical;
> >> +	} else {
> >> +		data->temp_critical = temp;
> >> +	}
> >> +
> >> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
> >> +		dev_warn(&pdev->dev,
> >> +			 "Missing default force shut down temp property in the DT.\n");
> >> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
> >> +	} else {
> >> +		data->temp_force_shut = temp;
> >> +	}
> >> +
> >> +	cpumask_set_cpu(0, &clip_cpus);
> >> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
> >> +	if (IS_ERR(data->cdev)) {
> >> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
> >> +		goto disable_clk;
> >> +	}
> >> +
> >> +	data->tz = thermal_zone_device_register("rockchip_thermal",
> >> +						ROCKCHIP_TRIP_NUM,
> >> +						0, data,
> >> +						&rockchip_tz_ops, NULL,
> >> +						p_tsadc_data->passive_delay,
> >> +						p_tsadc_data->polling_delay);
> >> +
> >> +	if (IS_ERR(data->tz)) {
> >> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
> >> +		goto fail_cpufreq_register;
> >> +	}
> >> +
> >> +	if (p_tsadc_data->irq_en) {
> >> +		data->irq = platform_get_irq(pdev, 0);
> >> +		if (data->irq < 0) {
> >> +			dev_err(&pdev->dev, "no irq resource?\n");
> >> +			goto fail_irq;
> >> +		}
> >> +
> >> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
> >> +				rockchip_thermal_alarm_irq_thread,
> >> +				IRQF_ONESHOT, "rockchip_thermal", data);
> >> +		if (ret < 0) {
> >> +			dev_err(&pdev->dev,
> >> +				"failed to request tsadc irq: %d\n", ret);
> >> +			goto fail_thermal_unregister;
> >> +		}
> >> +	}
> >> +
> >> +	rockchip_thermal_initialize(data);
> >> +	rockchip_thermal_control(data, true);
> >> +
> >> +	return 0;
> >> +
> >> +fail_thermal_unregister:
> >> +	thermal_zone_device_unregister(data->tz);
> >> +fail_irq:
> >> +fail_cpufreq_register:
> >> +	cpufreq_cooling_unregister(data->cdev);
> >> +disable_clk:
> >> +err_pclk:
> >> +	clk_disable_unprepare(data->pclk);
> >> +err_clk:
> >> +	clk_disable_unprepare(data->clk);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static int rockchip_thermal_remove(struct platform_device *pdev)
> >> +{
> >> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> >> +
> >> +	rockchip_thermal_control(data, false);
> >> +
> >> +	thermal_zone_device_unregister(data->tz);
> >> +	cpufreq_cooling_unregister(data->cdev);
> >> +	cpufreq_cooling_unregister(data->cdev);
> >> +
> > The above call is duplicated.
> 
> OK.
> >> +	clk_disable_unprepare(data->clk);
> >> +	clk_disable_unprepare(data->pclk);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +#ifdef CONFIG_PM_SLEEP
> >> +static int rockchip_thermal_suspend(struct device *dev)
> >> +{
> >> +	struct platform_device *pdev = to_platform_device(dev);
> >> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> >> +
> >> +	rockchip_thermal_control(data, false);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int rockchip_thermal_resume(struct device *dev)
> >> +{
> >> +	struct platform_device *pdev = to_platform_device(dev);
> >> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
> >> +
> >> +	rockchip_thermal_initialize(data);
> >> +	rockchip_thermal_control(data, true);
> >> +
> >> +	return 0;
> >> +}
> > Would you need to manage your clocks too in the suspend resume path
> > (data->clk and data->pclk)?
> yes.
> Usually,it's need disable to save power.

Yes, that's my point. Please consider handling clocks to improve power
savings.

> >> +#endif
> >> +
> >> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
> >> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
> >> +
> >> +static struct platform_driver rockchip_thermal_driver = {
> >> +	.driver = {
> >> +		   .name = "rockchip-thermal",
> >> +		   .owner = THIS_MODULE,
> >> +		   .pm = &rockchip_thermal_pm_ops,
> >> +		   .of_match_table = of_rockchip_thermal_match,
> >> +		   },
> >> +	.probe = rockchip_thermal_probe,
> >> +	.remove = rockchip_thermal_remove,
> >> +};
> >> +
> >> +module_platform_driver(rockchip_thermal_driver);
> >> +
> >> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
> >> +MODULE_AUTHOR("Rockchip, Inc.");
> >> +MODULE_LICENSE("GPL");
> > Your file header states GPL version two. Thus I suppose you meant:
> > +MODULE_LICENSE("GPL v2");
> >
> > right?
> >
> > Check include/linux/module.h for further clarifications.
> 
> But I think the  "GPL"  is support for thr GNU Public License v2 or later.

Exactly, if you intend to support v3, then it is fine. But your code
header states only V2.

> I will fix GPL v2 if I get it wrong.

If your license is GPLv2 only as mentioned in your header, please use 'GPL
v2' tag.

Cheers,

> 
> >> +MODULE_ALIAS("platform:rockchip-thermal");
> >> -- 
> >> 1.9.1
> >>
> >>
> > BR,
> >
> > Eduardo Valentin
> >
> >
> >
> 
> -- 
> Best regards,
> Caesar
> 
> 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 1/4] thermal: rockchip: add driver for thermal
  2014-09-10 12:46         ` Eduardo Valentin
  (?)
@ 2014-09-10 13:21           ` Caesar Wang
  -1 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-10 13:21 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: heiko, rui.zhang, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov, zhaoyifeng

Dear Eduardo,

在 2014/9/10 20:46, Eduardo Valentin 写道:
> Hello Caesar,
>
> On Wed, Sep 10, 2014 at 12:39:07PM +0800, Caesar Wang wrote:
>> Dear Eduardo,
>>
>> I'm  sorry for it.
>> I just received this message.Maybe my mailbox has a problem.
>
> No problems. You can take your time.
>
>> Thank you for your comments.
>>
>> 在 2014年08月31日 04:09, Eduardo Valentin 写道:
>>> Hello Ceasar,
>>>
>>> On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
>>>> Thermal is TS-ADC Controller module supports
>>>> user-defined mode and automatic mode.
>>>>
>>>> User-defined mode refers,TSADC all the control signals entirely by
>>>> software writing to register for direct control.
>>>>
>>>> Automaic mode refers to the module automatically poll TSADC output,
>>>> and the results were checked.If you find that the temperature High
>>>> in a period of time,an interrupt is generated to the processor
>>>> down-measures taken;if the temperature over a period of time High,
>>>> the resulting TSHUT gave CRU module,let it reset the entire chip,
>>>> or via GPIO give PMIC.
>>>>
>>>> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> I forgot to ask, is zhaoyifeng the correct name or is it a nickname?
:zhaoyifeng is chinese pinyin,Maybe I can correct name :Zhao Yi Feng or 
give him a English name:-D .

But his name is zhaoyifeng, so....
>>>> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>>>> ---
>>>>    drivers/thermal/Kconfig            |   9 +
>>>>    drivers/thermal/Makefile           |   1 +
>>>>    drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
>>>>    3 files changed, 679 insertions(+)
>>>>    create mode 100644 drivers/thermal/rockchip_thermal.c
>>>>
>>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>>> index f9a1386..a00aa1e 100644
>>>> --- a/drivers/thermal/Kconfig
>>>> +++ b/drivers/thermal/Kconfig
>>>> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
>>>>    	  Enable this to plug the SPEAr thermal sensor driver into the Linux
>>>>    	  thermal framework.
>>>>    
>>>> +config ROCKCHIP_THERMAL
>>>> +	tristate "Rockchip thermal driver"
>>>> +	depends on ARCH_ROCKCHIP
>>>> +	help
>>>> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
>>>> +	  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 RCAR_THERMAL
>>>>    	tristate "Renesas R-Car thermal driver"
>>>>    	depends on ARCH_SHMOBILE || COMPILE_TEST
>>>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>>>> index de0636a..b48b817 100644
>>>> --- a/drivers/thermal/Makefile
>>>> +++ b/drivers/thermal/Makefile
>>>> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
>>>>    
>>>>    # platform thermal drivers
>>>>    obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
>>>> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
>>>>    obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
>>>>    obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
>>>>    obj-y				+= samsung/
>>>> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
>>>> new file mode 100644
>>>> index 0000000..011f387
>>>> --- /dev/null
>>>> +++ b/drivers/thermal/rockchip_thermal.c
>>>> @@ -0,0 +1,669 @@
>>>> +/*
>>>> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
>>>> + *
>>>> + * 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/clk.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/of_irq.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/regulator/consumer.h>
>>>> +#include <linux/cpu_cooling.h>
>>>> +#include "thermal_core.h"
>>> Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
>>> sufficient?
>>>
>> yes, I will use linux/thermal.h.
>>>> +
>>>> +enum rockchip_thermal_trip {
>>>> +	ROCKCHIP_TRIP_PASSIVE,
>>>> +	ROCKCHIP_TRIP_CRITICAL,
>>>> +	ROCKCHIP_TRIP_NUM,
>>>> +};
>>>> +
>>> Why do you need your own trip types?
>>>
>>>> +struct rockchip_thermal_data {
>>>> +	const struct rockchip_tsadc_platform_data *pdata;
>>>> +	struct thermal_zone_device *tz;
>>>> +	struct thermal_cooling_device *cdev;
>>>> +	enum thermal_device_mode mode;
>>>> +	void __iomem *regs;
>>>> +
>>>> +	signed long temp_passive;
>>>> +	signed long temp_critical;
>>>> +	signed long temp_force_shut;
>>>> +	signed long alarm_temp;
>>>> +	signed long last_temp;
>>>> +	bool irq_enabled;
>>>> +	int irq;
>>>> +	struct clk *clk;
>>>> +	struct clk *pclk;
>>>> +};
>>>> +
>>>> +struct rockchip_tsadc_platform_data {
>>>> +	u8 irq_en;
>>>> +	signed long temp_passive;
>>>> +	signed long temp_critical;
>>>> +	signed long temp_force_shut;
>>>> +	int passive_delay;
>>>> +	int polling_delay;
>>>> +
>>>> +	int (*irq_handle)(void __iomem *reg);
>>>> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
>>>> +	int (*control)(void __iomem *reg, bool on);
>>>> +	u32 (*code_to_temp)(int temp);
>>>> +	u32 (*temp_to_code)(int temp);
>>>> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
>>>> +};
>>>> +
>>>> +/*TSADC V2 Sensor info define:*/
>>>> +#define TSADCV2_AUTO_CON			0x04
>>>> +#define TSADCV2_INT_EN				0x08
>>>> +#define TSADCV2_INT_PD				0x0c
>>>> +#define TSADCV2_DATA1				0x24
>>>> +#define TSADCV2_COMP1_INT			0x34
>>>> +#define TSADCV2_COMP1_SHUT			0x44
>>>> +#define TSADCV2_AUTO_PERIOD			0x68
>>>> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
>>>> +
>>>> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
>>>> +#define TSADCV2_AUTO_EN				(1 << 0)
>>>> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
>>>> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
>>>> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
>>>> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
>>>> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
>>>> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
>>>> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
>>>> +
>>> The above bits can be defined with BIT() macro, right?
>> Yes. The Bit() will be more resonable..
>>>    Something like:
>>> +#define TSADCV2_INT_SRC1_STATUS			BIT(1)
>>>
>>>
>>>> +#define TSADCV2_DATA_MASK			0xfff
>>>> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
>>>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
>>>> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
>>>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
>>>> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
>>>> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
>>>> +
>>>> +struct tsadc_table {
>>>> +	int code;
>>>> +	int temp;
>>>> +};
>>>> +
>>>> +static const struct tsadc_table v2_code_table[] = {
>>>> +	{TSADCV2_DATA_MASK, -40},
>>>> +	{3800, -40},
>>>> +	{3792, -35},
>>>> +	{3783, -30},
>>>> +	{3774, -25},
>>>> +	{3765, -20},
>>>> +	{3756, -15},
>>>> +	{3747, -10},
>>>> +	{3737, -5},
>>>> +	{3728, 0},
>>>> +	{3718, 5},
>>>> +	{3708, 10},
>>>> +	{3698, 15},
>>>> +	{3688, 20},
>>>> +	{3678, 25},
>>>> +	{3667, 30},
>>>> +	{3656, 35},
>>>> +	{3645, 40},
>>>> +	{3634, 45},
>>>> +	{3623, 50},
>>>> +	{3611, 55},
>>>> +	{3600, 60},
>>>> +	{3588, 65},
>>>> +	{3575, 70},
>>>> +	{3563, 75},
>>>> +	{3550, 80},
>>>> +	{3537, 85},
>>>> +	{3524, 90},
>>>> +	{3510, 95},
>>>> +	{3496, 100},
>>>> +	{3482, 105},
>>>> +	{3467, 110},
>>>> +	{3452, 115},
>>>> +	{3437, 120},
>>>> +	{3421, 125},
>>>> +	{0, 125},
>>>> +};
>>>> +
>>>> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
>>>> +{
>>>> +	u32 val;
>>>> +
>>>> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
>>>> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
>>> Why do you need to clear bit 8? Why hardcoded?
>> The bit 8 set 0 to clear the interrupt.
>>
> Would it make sense to create a macro for this?

OK .
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static u32 rk_tsadcv2_temp_to_code(int temp)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>>>> +		if (temp <= v2_code_table[i].temp && temp >
>>>> +		    v2_code_table[i - 1].temp)
>>>> +			return v2_code_table[i].code;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static u32 rk_tsadcv2_code_to_temp(int code)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>>>> +		if (code <= v2_code_table[i].code && code >
>>>> +		    v2_code_table[i + 1].code){
>>>> +			return v2_code_table[i].temp;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> I know the table is not something too big, but considering it is ordered
>>> by either ADC value code or by temp, at least one of the above searching function
>>> may be more efficient, right?
>> Yes, use the point will be more efficient.
>>>> +
>>>> +static int rk_tsadcv2_initialize(void __iomem *regs,
>>>> +				 signed long temp_force_shut)
>>>> +{
>>>> +	int shutdown_value;
>>>> +
>>>> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
>>>> +	/* Enable measurements at ~ 10 Hz */
>>> Does it leave the sampling clock at 10Hz?
>> yes.
> ok
>
>
>>> Is this clock exposed via
>>> clock framework?
>> The clock is divided by data->clk.
> ok
>
>>>> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
>>>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
>>>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
>>>> +		       TSADCV2_AUTO_PERIOD_HT);
>>>> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
>>>> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
>>>> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
>>>> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
>>>> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
>>>> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
>>>> +		       TSADCV2_INT_EN);
>>>> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
>>>> +		       TSADCV2_AUTO_CON);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
>>>> +{
>>>> +	u32 val;
>>>> +
>>>> +	if (on) {
>>>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>>>> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
>>>> +	} else {
>>>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>>>> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
>>>> +			       regs + TSADCV2_AUTO_CON);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
>>>> +{
>>>> +	int alarm_value;
>>>> +
>>>> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
>>>> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
>>>> +}
>>>> +
>>>> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
>>>> +	.irq_en = 1,
>>>> +	.temp_passive = 85000,
>>>> +	.temp_critical = 100000,
>>>> +	.temp_force_shut = 120000,
>>>> +	.passive_delay = 2000,
>>>> +	.polling_delay = 1000,
>>>> +	.irq_handle = rk_tsadcv2_irq_handle,
>>>> +	.initialize = rk_tsadcv2_initialize,
>>>> +	.control = rk_tsadcv2_control,
>>>> +	.code_to_temp = rk_tsadcv2_code_to_temp,
>>>> +	.temp_to_code = rk_tsadcv2_temp_to_code,
>>>> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
>>>> +};
>>> shall the above struct be also static?
>> OK.
>>>> +
>>>> +static const struct of_device_id of_rockchip_thermal_match[] = {
>>>> +	{
>>>> +		.compatible = "rockchip,rk3288-tsadc",
>>>> +		.data = (void *)&rk3288_tsadc_data,
>>>> +	},
>>>> +	{ /* end */ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
>>>> +
>>>> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
>>>> +				    signed long alarm_temp)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	data->alarm_temp = alarm_temp;
>>>> +	if (p_tsadc_data->set_alarm_temp)
>>>> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
>>>> +}
>>>> +
>>>> +static int rockchip_get_temp(struct thermal_zone_device *tz,
>>>> +			     unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +	u32 val;
>>>> +
>>>> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
>>>> +	*temp = p_tsadc_data->code_to_temp(val);
>>>> +
>>>> +	/* Update alarm value to next higher trip point */
>>>> +	if (data->alarm_temp == data->temp_passive && *temp >=
>>>> +	    data->temp_passive)
>>>> +		rockchip_set_alarm_temp(data, data->temp_critical);
>>>> +
>>>> +	if (data->alarm_temp == data->temp_critical && *temp <
>>>> +	    data->temp_passive) {
>>>> +		rockchip_set_alarm_temp(data, data->temp_passive);
>>>> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
>>>> +			data->alarm_temp / 1000);
>>>> +	}
>>>> +
>>>> +	if (*temp != data->last_temp) {
>>>> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
>>>> +		data->last_temp = *temp;
>>>> +	}
>>>> +
>>>> +	/* Reenable alarm IRQ if temperature below alarm temperature */
>>>> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
>>>> +		data->irq_enabled = true;
>>>> +		enable_irq(data->irq);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (p_tsadc_data->initialize)
>>>> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
>>>> +	rockchip_set_alarm_temp(data, data->temp_passive);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
>>>> +				     bool on)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (p_tsadc_data->control)
>>>> +		p_tsadc_data->control(data->regs, on);
>>>> +
>>>> +	if (on) {
>>>> +		data->irq_enabled = true;
>>>> +		data->mode = THERMAL_DEVICE_ENABLED;
>>>> +	} else {
>>>> +		data->irq_enabled = false;
>>>> +		data->mode = THERMAL_DEVICE_DISABLED;
>>>> +	}
>>>> +}
>>>> +
>>>> +static int rockchip_get_mode(struct thermal_zone_device *tz,
>>>> +			     enum thermal_device_mode *mode)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*mode = data->mode;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_set_mode(struct thermal_zone_device *tz,
>>>> +			     enum thermal_device_mode mode)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (mode == THERMAL_DEVICE_ENABLED) {
>>>> +		tz->polling_delay = p_tsadc_data->polling_delay;
>>>> +		tz->passive_delay = p_tsadc_data->passive_delay;
>>>> +		if (!data->irq_enabled) {
>>>> +			data->irq_enabled = true;
>>>> +			enable_irq(data->irq);
>>>> +		}
>>>> +	} else {
>>>> +		tz->polling_delay = 0;
>>>> +		tz->passive_delay = 0;
>>>> +		if (data->irq_enabled) {
>>>> +			disable_irq(data->irq);
>>>> +			data->irq_enabled = false;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	data->mode = mode;
>>>> +	thermal_zone_device_update(tz);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
>>>> +				  enum thermal_trip_type *type)
>>>> +{
>>>> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
>>>> +		 THERMAL_TRIP_CRITICAL;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
>>>> +				  unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*temp = data->temp_critical;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
>>>> +				  unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
>>>> +		 data->temp_critical;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
>>>> +				  unsigned long temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
>>>> +		return -EPERM;
>>>> +
>>>> +	data->temp_passive = temp;
>>>> +	rockchip_set_alarm_temp(data, temp);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_bind(struct thermal_zone_device *tz,
>>>> +			 struct thermal_cooling_device *cdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
>>>> +					       THERMAL_NO_LIMIT,
>>>> +					       THERMAL_NO_LIMIT);
>>>> +	if (ret) {
>>>> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>>>> +			tz->type, cdev->type, ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_unbind(struct thermal_zone_device *tz,
>>>> +			   struct thermal_cooling_device *cdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = thermal_zone_unbind_cooling_device(tz,
>>>> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
>>>> +	if (ret) {
>>>> +		dev_err(&tz->device,
>>>> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
>>>> +			cdev->type, ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> The method of binding and unbinding used above requires you to check if
>>> you are binding to the right cdev. If in your system you register more
>>> than one cdev, say someone loads the power supply core, which in turns
>>> register a cooling device for charging, your thermal zone will bind it
>>> to TRIP_PASSIVE. It will happen to any cooling device that eventually
>>> gets registered to the thermal framework. Is that the desired outcome?
>> Yes,I will use the generic trip points in the dts and fix it in the
>> thermal driver.
> great
>
>>> If not, you may want to compare the paramenter cdev to your data->cdev.
>>>
>>>> +
>>>> +static struct thermal_zone_device_ops rockchip_tz_ops = {
>>>> +	.bind = rockchip_bind,
>>>> +	.unbind = rockchip_unbind,
>>>> +	.get_temp = rockchip_get_temp,
>>>> +	.get_mode = rockchip_get_mode,
>>>> +	.set_mode = rockchip_set_mode,
>>>> +	.get_trip_type = rockchip_get_trip_type,
>>>> +	.get_trip_temp = rockchip_get_trip_temp,
>>>> +	.get_crit_temp = rockchip_get_crit_temp,
>>>> +	.set_trip_temp = rockchip_set_trip_temp,
>>>> +};
>>>> +
>>>> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = data;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
>>>> +		data->alarm_temp / 1000);
>>>> +
>>>> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
>>>> +		p_tsadc_data->irq_handle(data->regs);
>>>> +
>>>> +	thermal_zone_device_update(data->tz);
>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_probe(struct platform_device *pdev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
>>>> +	struct cpumask clip_cpus;
>>>> +	struct resource *res;
>>>> +	const struct of_device_id *match;
>>>> +	int ret, temp;
>>>> +
>>>> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
>>>> +			    GFP_KERNEL);
>>>> +	if (!data)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
>>>> +	if (IS_ERR(data->regs)) {
>>>> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
>>>> +			data->regs);
>>>> +		return PTR_ERR(data->regs);
>>>> +	}
>>>> +
>>>> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
>>>> +	if (!match)
>>>> +		return -ENXIO;
>>>> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
>>>> +	if (!data->pdata)
>>>> +		return -EINVAL;
>>>> +	p_tsadc_data = data->pdata;
>>>> +
>>>> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
>>>> +	if (IS_ERR(data->clk)) {
>>>> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
>>>> +		return PTR_ERR(data->clk);
>>>> +	}
>>>> +
>>>> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
>>>> +	if (IS_ERR(data->pclk)) {
>>>> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
>>>> +		return PTR_ERR(data->pclk);
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	* Use a default of 10KHz for the converter clock.
>>>> +	* This may become user-configurable in the future.
>>>> +	*/
>>>> +	ret = clk_set_rate(data->clk, 10000);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(data->clk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
>>>> +		goto err_clk;
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(data->pclk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to enable pclk\n");
>>>> +		goto err_pclk;
>>>> +	}
>>>> +
>>>> +	platform_set_drvdata(pdev, data);
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default passive temp property in the DT.\n");
>>>> +		data->temp_passive = p_tsadc_data->temp_passive;
>>>> +	} else {
>>>> +		data->temp_passive = temp;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default critical temp property in the DT.\n");
>>>> +		data->temp_critical = p_tsadc_data->temp_critical;
>>>> +	} else {
>>>> +		data->temp_critical = temp;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default force shut down temp property in the DT.\n");
>>>> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
>>>> +	} else {
>>>> +		data->temp_force_shut = temp;
>>>> +	}
>>>> +
>>>> +	cpumask_set_cpu(0, &clip_cpus);
>>>> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
>>>> +	if (IS_ERR(data->cdev)) {
>>>> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
>>>> +		goto disable_clk;
>>>> +	}
>>>> +
>>>> +	data->tz = thermal_zone_device_register("rockchip_thermal",
>>>> +						ROCKCHIP_TRIP_NUM,
>>>> +						0, data,
>>>> +						&rockchip_tz_ops, NULL,
>>>> +						p_tsadc_data->passive_delay,
>>>> +						p_tsadc_data->polling_delay);
>>>> +
>>>> +	if (IS_ERR(data->tz)) {
>>>> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
>>>> +		goto fail_cpufreq_register;
>>>> +	}
>>>> +
>>>> +	if (p_tsadc_data->irq_en) {
>>>> +		data->irq = platform_get_irq(pdev, 0);
>>>> +		if (data->irq < 0) {
>>>> +			dev_err(&pdev->dev, "no irq resource?\n");
>>>> +			goto fail_irq;
>>>> +		}
>>>> +
>>>> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
>>>> +				rockchip_thermal_alarm_irq_thread,
>>>> +				IRQF_ONESHOT, "rockchip_thermal", data);
>>>> +		if (ret < 0) {
>>>> +			dev_err(&pdev->dev,
>>>> +				"failed to request tsadc irq: %d\n", ret);
>>>> +			goto fail_thermal_unregister;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	rockchip_thermal_initialize(data);
>>>> +	rockchip_thermal_control(data, true);
>>>> +
>>>> +	return 0;
>>>> +
>>>> +fail_thermal_unregister:
>>>> +	thermal_zone_device_unregister(data->tz);
>>>> +fail_irq:
>>>> +fail_cpufreq_register:
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +disable_clk:
>>>> +err_pclk:
>>>> +	clk_disable_unprepare(data->pclk);
>>>> +err_clk:
>>>> +	clk_disable_unprepare(data->clk);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_control(data, false);
>>>> +
>>>> +	thermal_zone_device_unregister(data->tz);
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +
>>> The above call is duplicated.
>> OK.
>>>> +	clk_disable_unprepare(data->clk);
>>>> +	clk_disable_unprepare(data->pclk);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int rockchip_thermal_suspend(struct device *dev)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_control(data, false);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_resume(struct device *dev)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_initialize(data);
>>>> +	rockchip_thermal_control(data, true);
>>>> +
>>>> +	return 0;
>>>> +}
>>> Would you need to manage your clocks too in the suspend resume path
>>> (data->clk and data->pclk)?
>> yes.
>> Usually,it's need disable to save power.
> Yes, that's my point. Please consider handling clocks to improve power
> savings.
>
>>>> +#endif
>>>> +
>>>> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
>>>> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
>>>> +
>>>> +static struct platform_driver rockchip_thermal_driver = {
>>>> +	.driver = {
>>>> +		   .name = "rockchip-thermal",
>>>> +		   .owner = THIS_MODULE,
>>>> +		   .pm = &rockchip_thermal_pm_ops,
>>>> +		   .of_match_table = of_rockchip_thermal_match,
>>>> +		   },
>>>> +	.probe = rockchip_thermal_probe,
>>>> +	.remove = rockchip_thermal_remove,
>>>> +};
>>>> +
>>>> +module_platform_driver(rockchip_thermal_driver);
>>>> +
>>>> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
>>>> +MODULE_AUTHOR("Rockchip, Inc.");
>>>> +MODULE_LICENSE("GPL");
>>> Your file header states GPL version two. Thus I suppose you meant:
>>> +MODULE_LICENSE("GPL v2");
>>>
>>> right?
>>>
>>> Check include/linux/module.h for further clarifications.
>> But I think the  "GPL"  is support for thr GNU Public License v2 or later.
> Exactly, if you intend to support v3, then it is fine. But your code
> header states only V2.
>
>> I will fix GPL v2 if I get it wrong.
> If your license is GPLv2 only as mentioned in your header, please use 'GPL
> v2' tag.
>
> Cheers,
>
>>>> +MODULE_ALIAS("platform:rockchip-thermal");
>>>> -- 
>>>> 1.9.1
>>>>
>>>>
>>> BR,
>>>
>>> Eduardo Valentin
>>>
>>>
>>>
>> -- 
>> Best regards,
>> Caesar
>>
>>
>
>

-- 
Best regards,
Caesar



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 1/4] thermal: rockchip: add driver for thermal
@ 2014-09-10 13:21           ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-10 13:21 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: heiko-4mtYJXux2i+zQB+pC5nmwQ, rui.zhang-ral2JQCrhuEAvxtiuMwx3w,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	huangtao-TNX95d0MmH7DzftRWevZcw, cf-TNX95d0MmH7DzftRWevZcw,
	dianders-F7+t8E8rja9g9hUCZPvPmw, dtor-F7+t8E8rja9g9hUCZPvPmw,
	zyw-TNX95d0MmH7DzftRWevZcw, addy.ke-TNX95d0MmH7DzftRWevZcw,
	dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w, zhaoyifeng

Dear Eduardo,

在 2014/9/10 20:46, Eduardo Valentin 写道:
> Hello Caesar,
>
> On Wed, Sep 10, 2014 at 12:39:07PM +0800, Caesar Wang wrote:
>> Dear Eduardo,
>>
>> I'm  sorry for it.
>> I just received this message.Maybe my mailbox has a problem.
>
> No problems. You can take your time.
>
>> Thank you for your comments.
>>
>> 在 2014年08月31日 04:09, Eduardo Valentin 写道:
>>> Hello Ceasar,
>>>
>>> On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
>>>> Thermal is TS-ADC Controller module supports
>>>> user-defined mode and automatic mode.
>>>>
>>>> User-defined mode refers,TSADC all the control signals entirely by
>>>> software writing to register for direct control.
>>>>
>>>> Automaic mode refers to the module automatically poll TSADC output,
>>>> and the results were checked.If you find that the temperature High
>>>> in a period of time,an interrupt is generated to the processor
>>>> down-measures taken;if the temperature over a period of time High,
>>>> the resulting TSHUT gave CRU module,let it reset the entire chip,
>>>> or via GPIO give PMIC.
>>>>
>>>> Signed-off-by: zhaoyifeng <zyf-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> I forgot to ask, is zhaoyifeng the correct name or is it a nickname?
:zhaoyifeng is chinese pinyin,Maybe I can correct name :Zhao Yi Feng or 
give him a English name:-D .

But his name is zhaoyifeng, so....
>>>> Signed-off-by: Caesar Wang <caesar.wang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>>>> ---
>>>>    drivers/thermal/Kconfig            |   9 +
>>>>    drivers/thermal/Makefile           |   1 +
>>>>    drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
>>>>    3 files changed, 679 insertions(+)
>>>>    create mode 100644 drivers/thermal/rockchip_thermal.c
>>>>
>>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>>> index f9a1386..a00aa1e 100644
>>>> --- a/drivers/thermal/Kconfig
>>>> +++ b/drivers/thermal/Kconfig
>>>> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
>>>>    	  Enable this to plug the SPEAr thermal sensor driver into the Linux
>>>>    	  thermal framework.
>>>>    
>>>> +config ROCKCHIP_THERMAL
>>>> +	tristate "Rockchip thermal driver"
>>>> +	depends on ARCH_ROCKCHIP
>>>> +	help
>>>> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
>>>> +	  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 RCAR_THERMAL
>>>>    	tristate "Renesas R-Car thermal driver"
>>>>    	depends on ARCH_SHMOBILE || COMPILE_TEST
>>>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>>>> index de0636a..b48b817 100644
>>>> --- a/drivers/thermal/Makefile
>>>> +++ b/drivers/thermal/Makefile
>>>> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
>>>>    
>>>>    # platform thermal drivers
>>>>    obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
>>>> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
>>>>    obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
>>>>    obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
>>>>    obj-y				+= samsung/
>>>> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
>>>> new file mode 100644
>>>> index 0000000..011f387
>>>> --- /dev/null
>>>> +++ b/drivers/thermal/rockchip_thermal.c
>>>> @@ -0,0 +1,669 @@
>>>> +/*
>>>> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
>>>> + *
>>>> + * 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/clk.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/of_irq.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/regulator/consumer.h>
>>>> +#include <linux/cpu_cooling.h>
>>>> +#include "thermal_core.h"
>>> Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
>>> sufficient?
>>>
>> yes, I will use linux/thermal.h.
>>>> +
>>>> +enum rockchip_thermal_trip {
>>>> +	ROCKCHIP_TRIP_PASSIVE,
>>>> +	ROCKCHIP_TRIP_CRITICAL,
>>>> +	ROCKCHIP_TRIP_NUM,
>>>> +};
>>>> +
>>> Why do you need your own trip types?
>>>
>>>> +struct rockchip_thermal_data {
>>>> +	const struct rockchip_tsadc_platform_data *pdata;
>>>> +	struct thermal_zone_device *tz;
>>>> +	struct thermal_cooling_device *cdev;
>>>> +	enum thermal_device_mode mode;
>>>> +	void __iomem *regs;
>>>> +
>>>> +	signed long temp_passive;
>>>> +	signed long temp_critical;
>>>> +	signed long temp_force_shut;
>>>> +	signed long alarm_temp;
>>>> +	signed long last_temp;
>>>> +	bool irq_enabled;
>>>> +	int irq;
>>>> +	struct clk *clk;
>>>> +	struct clk *pclk;
>>>> +};
>>>> +
>>>> +struct rockchip_tsadc_platform_data {
>>>> +	u8 irq_en;
>>>> +	signed long temp_passive;
>>>> +	signed long temp_critical;
>>>> +	signed long temp_force_shut;
>>>> +	int passive_delay;
>>>> +	int polling_delay;
>>>> +
>>>> +	int (*irq_handle)(void __iomem *reg);
>>>> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
>>>> +	int (*control)(void __iomem *reg, bool on);
>>>> +	u32 (*code_to_temp)(int temp);
>>>> +	u32 (*temp_to_code)(int temp);
>>>> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
>>>> +};
>>>> +
>>>> +/*TSADC V2 Sensor info define:*/
>>>> +#define TSADCV2_AUTO_CON			0x04
>>>> +#define TSADCV2_INT_EN				0x08
>>>> +#define TSADCV2_INT_PD				0x0c
>>>> +#define TSADCV2_DATA1				0x24
>>>> +#define TSADCV2_COMP1_INT			0x34
>>>> +#define TSADCV2_COMP1_SHUT			0x44
>>>> +#define TSADCV2_AUTO_PERIOD			0x68
>>>> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
>>>> +
>>>> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
>>>> +#define TSADCV2_AUTO_EN				(1 << 0)
>>>> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
>>>> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
>>>> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
>>>> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
>>>> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
>>>> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
>>>> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
>>>> +
>>> The above bits can be defined with BIT() macro, right?
>> Yes. The Bit() will be more resonable..
>>>    Something like:
>>> +#define TSADCV2_INT_SRC1_STATUS			BIT(1)
>>>
>>>
>>>> +#define TSADCV2_DATA_MASK			0xfff
>>>> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
>>>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
>>>> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
>>>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
>>>> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
>>>> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
>>>> +
>>>> +struct tsadc_table {
>>>> +	int code;
>>>> +	int temp;
>>>> +};
>>>> +
>>>> +static const struct tsadc_table v2_code_table[] = {
>>>> +	{TSADCV2_DATA_MASK, -40},
>>>> +	{3800, -40},
>>>> +	{3792, -35},
>>>> +	{3783, -30},
>>>> +	{3774, -25},
>>>> +	{3765, -20},
>>>> +	{3756, -15},
>>>> +	{3747, -10},
>>>> +	{3737, -5},
>>>> +	{3728, 0},
>>>> +	{3718, 5},
>>>> +	{3708, 10},
>>>> +	{3698, 15},
>>>> +	{3688, 20},
>>>> +	{3678, 25},
>>>> +	{3667, 30},
>>>> +	{3656, 35},
>>>> +	{3645, 40},
>>>> +	{3634, 45},
>>>> +	{3623, 50},
>>>> +	{3611, 55},
>>>> +	{3600, 60},
>>>> +	{3588, 65},
>>>> +	{3575, 70},
>>>> +	{3563, 75},
>>>> +	{3550, 80},
>>>> +	{3537, 85},
>>>> +	{3524, 90},
>>>> +	{3510, 95},
>>>> +	{3496, 100},
>>>> +	{3482, 105},
>>>> +	{3467, 110},
>>>> +	{3452, 115},
>>>> +	{3437, 120},
>>>> +	{3421, 125},
>>>> +	{0, 125},
>>>> +};
>>>> +
>>>> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
>>>> +{
>>>> +	u32 val;
>>>> +
>>>> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
>>>> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
>>> Why do you need to clear bit 8? Why hardcoded?
>> The bit 8 set 0 to clear the interrupt.
>>
> Would it make sense to create a macro for this?

OK .
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static u32 rk_tsadcv2_temp_to_code(int temp)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>>>> +		if (temp <= v2_code_table[i].temp && temp >
>>>> +		    v2_code_table[i - 1].temp)
>>>> +			return v2_code_table[i].code;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static u32 rk_tsadcv2_code_to_temp(int code)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>>>> +		if (code <= v2_code_table[i].code && code >
>>>> +		    v2_code_table[i + 1].code){
>>>> +			return v2_code_table[i].temp;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> I know the table is not something too big, but considering it is ordered
>>> by either ADC value code or by temp, at least one of the above searching function
>>> may be more efficient, right?
>> Yes, use the point will be more efficient.
>>>> +
>>>> +static int rk_tsadcv2_initialize(void __iomem *regs,
>>>> +				 signed long temp_force_shut)
>>>> +{
>>>> +	int shutdown_value;
>>>> +
>>>> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
>>>> +	/* Enable measurements at ~ 10 Hz */
>>> Does it leave the sampling clock at 10Hz?
>> yes.
> ok
>
>
>>> Is this clock exposed via
>>> clock framework?
>> The clock is divided by data->clk.
> ok
>
>>>> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
>>>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
>>>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
>>>> +		       TSADCV2_AUTO_PERIOD_HT);
>>>> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
>>>> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
>>>> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
>>>> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
>>>> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
>>>> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
>>>> +		       TSADCV2_INT_EN);
>>>> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
>>>> +		       TSADCV2_AUTO_CON);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
>>>> +{
>>>> +	u32 val;
>>>> +
>>>> +	if (on) {
>>>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>>>> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
>>>> +	} else {
>>>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>>>> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
>>>> +			       regs + TSADCV2_AUTO_CON);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
>>>> +{
>>>> +	int alarm_value;
>>>> +
>>>> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
>>>> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
>>>> +}
>>>> +
>>>> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
>>>> +	.irq_en = 1,
>>>> +	.temp_passive = 85000,
>>>> +	.temp_critical = 100000,
>>>> +	.temp_force_shut = 120000,
>>>> +	.passive_delay = 2000,
>>>> +	.polling_delay = 1000,
>>>> +	.irq_handle = rk_tsadcv2_irq_handle,
>>>> +	.initialize = rk_tsadcv2_initialize,
>>>> +	.control = rk_tsadcv2_control,
>>>> +	.code_to_temp = rk_tsadcv2_code_to_temp,
>>>> +	.temp_to_code = rk_tsadcv2_temp_to_code,
>>>> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
>>>> +};
>>> shall the above struct be also static?
>> OK.
>>>> +
>>>> +static const struct of_device_id of_rockchip_thermal_match[] = {
>>>> +	{
>>>> +		.compatible = "rockchip,rk3288-tsadc",
>>>> +		.data = (void *)&rk3288_tsadc_data,
>>>> +	},
>>>> +	{ /* end */ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
>>>> +
>>>> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
>>>> +				    signed long alarm_temp)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	data->alarm_temp = alarm_temp;
>>>> +	if (p_tsadc_data->set_alarm_temp)
>>>> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
>>>> +}
>>>> +
>>>> +static int rockchip_get_temp(struct thermal_zone_device *tz,
>>>> +			     unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +	u32 val;
>>>> +
>>>> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
>>>> +	*temp = p_tsadc_data->code_to_temp(val);
>>>> +
>>>> +	/* Update alarm value to next higher trip point */
>>>> +	if (data->alarm_temp == data->temp_passive && *temp >=
>>>> +	    data->temp_passive)
>>>> +		rockchip_set_alarm_temp(data, data->temp_critical);
>>>> +
>>>> +	if (data->alarm_temp == data->temp_critical && *temp <
>>>> +	    data->temp_passive) {
>>>> +		rockchip_set_alarm_temp(data, data->temp_passive);
>>>> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
>>>> +			data->alarm_temp / 1000);
>>>> +	}
>>>> +
>>>> +	if (*temp != data->last_temp) {
>>>> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
>>>> +		data->last_temp = *temp;
>>>> +	}
>>>> +
>>>> +	/* Reenable alarm IRQ if temperature below alarm temperature */
>>>> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
>>>> +		data->irq_enabled = true;
>>>> +		enable_irq(data->irq);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (p_tsadc_data->initialize)
>>>> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
>>>> +	rockchip_set_alarm_temp(data, data->temp_passive);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
>>>> +				     bool on)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (p_tsadc_data->control)
>>>> +		p_tsadc_data->control(data->regs, on);
>>>> +
>>>> +	if (on) {
>>>> +		data->irq_enabled = true;
>>>> +		data->mode = THERMAL_DEVICE_ENABLED;
>>>> +	} else {
>>>> +		data->irq_enabled = false;
>>>> +		data->mode = THERMAL_DEVICE_DISABLED;
>>>> +	}
>>>> +}
>>>> +
>>>> +static int rockchip_get_mode(struct thermal_zone_device *tz,
>>>> +			     enum thermal_device_mode *mode)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*mode = data->mode;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_set_mode(struct thermal_zone_device *tz,
>>>> +			     enum thermal_device_mode mode)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (mode == THERMAL_DEVICE_ENABLED) {
>>>> +		tz->polling_delay = p_tsadc_data->polling_delay;
>>>> +		tz->passive_delay = p_tsadc_data->passive_delay;
>>>> +		if (!data->irq_enabled) {
>>>> +			data->irq_enabled = true;
>>>> +			enable_irq(data->irq);
>>>> +		}
>>>> +	} else {
>>>> +		tz->polling_delay = 0;
>>>> +		tz->passive_delay = 0;
>>>> +		if (data->irq_enabled) {
>>>> +			disable_irq(data->irq);
>>>> +			data->irq_enabled = false;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	data->mode = mode;
>>>> +	thermal_zone_device_update(tz);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
>>>> +				  enum thermal_trip_type *type)
>>>> +{
>>>> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
>>>> +		 THERMAL_TRIP_CRITICAL;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
>>>> +				  unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*temp = data->temp_critical;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
>>>> +				  unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
>>>> +		 data->temp_critical;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
>>>> +				  unsigned long temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
>>>> +		return -EPERM;
>>>> +
>>>> +	data->temp_passive = temp;
>>>> +	rockchip_set_alarm_temp(data, temp);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_bind(struct thermal_zone_device *tz,
>>>> +			 struct thermal_cooling_device *cdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
>>>> +					       THERMAL_NO_LIMIT,
>>>> +					       THERMAL_NO_LIMIT);
>>>> +	if (ret) {
>>>> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>>>> +			tz->type, cdev->type, ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_unbind(struct thermal_zone_device *tz,
>>>> +			   struct thermal_cooling_device *cdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = thermal_zone_unbind_cooling_device(tz,
>>>> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
>>>> +	if (ret) {
>>>> +		dev_err(&tz->device,
>>>> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
>>>> +			cdev->type, ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> The method of binding and unbinding used above requires you to check if
>>> you are binding to the right cdev. If in your system you register more
>>> than one cdev, say someone loads the power supply core, which in turns
>>> register a cooling device for charging, your thermal zone will bind it
>>> to TRIP_PASSIVE. It will happen to any cooling device that eventually
>>> gets registered to the thermal framework. Is that the desired outcome?
>> Yes,I will use the generic trip points in the dts and fix it in the
>> thermal driver.
> great
>
>>> If not, you may want to compare the paramenter cdev to your data->cdev.
>>>
>>>> +
>>>> +static struct thermal_zone_device_ops rockchip_tz_ops = {
>>>> +	.bind = rockchip_bind,
>>>> +	.unbind = rockchip_unbind,
>>>> +	.get_temp = rockchip_get_temp,
>>>> +	.get_mode = rockchip_get_mode,
>>>> +	.set_mode = rockchip_set_mode,
>>>> +	.get_trip_type = rockchip_get_trip_type,
>>>> +	.get_trip_temp = rockchip_get_trip_temp,
>>>> +	.get_crit_temp = rockchip_get_crit_temp,
>>>> +	.set_trip_temp = rockchip_set_trip_temp,
>>>> +};
>>>> +
>>>> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = data;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
>>>> +		data->alarm_temp / 1000);
>>>> +
>>>> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
>>>> +		p_tsadc_data->irq_handle(data->regs);
>>>> +
>>>> +	thermal_zone_device_update(data->tz);
>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_probe(struct platform_device *pdev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
>>>> +	struct cpumask clip_cpus;
>>>> +	struct resource *res;
>>>> +	const struct of_device_id *match;
>>>> +	int ret, temp;
>>>> +
>>>> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
>>>> +			    GFP_KERNEL);
>>>> +	if (!data)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
>>>> +	if (IS_ERR(data->regs)) {
>>>> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
>>>> +			data->regs);
>>>> +		return PTR_ERR(data->regs);
>>>> +	}
>>>> +
>>>> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
>>>> +	if (!match)
>>>> +		return -ENXIO;
>>>> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
>>>> +	if (!data->pdata)
>>>> +		return -EINVAL;
>>>> +	p_tsadc_data = data->pdata;
>>>> +
>>>> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
>>>> +	if (IS_ERR(data->clk)) {
>>>> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
>>>> +		return PTR_ERR(data->clk);
>>>> +	}
>>>> +
>>>> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
>>>> +	if (IS_ERR(data->pclk)) {
>>>> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
>>>> +		return PTR_ERR(data->pclk);
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	* Use a default of 10KHz for the converter clock.
>>>> +	* This may become user-configurable in the future.
>>>> +	*/
>>>> +	ret = clk_set_rate(data->clk, 10000);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(data->clk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
>>>> +		goto err_clk;
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(data->pclk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to enable pclk\n");
>>>> +		goto err_pclk;
>>>> +	}
>>>> +
>>>> +	platform_set_drvdata(pdev, data);
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default passive temp property in the DT.\n");
>>>> +		data->temp_passive = p_tsadc_data->temp_passive;
>>>> +	} else {
>>>> +		data->temp_passive = temp;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default critical temp property in the DT.\n");
>>>> +		data->temp_critical = p_tsadc_data->temp_critical;
>>>> +	} else {
>>>> +		data->temp_critical = temp;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default force shut down temp property in the DT.\n");
>>>> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
>>>> +	} else {
>>>> +		data->temp_force_shut = temp;
>>>> +	}
>>>> +
>>>> +	cpumask_set_cpu(0, &clip_cpus);
>>>> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
>>>> +	if (IS_ERR(data->cdev)) {
>>>> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
>>>> +		goto disable_clk;
>>>> +	}
>>>> +
>>>> +	data->tz = thermal_zone_device_register("rockchip_thermal",
>>>> +						ROCKCHIP_TRIP_NUM,
>>>> +						0, data,
>>>> +						&rockchip_tz_ops, NULL,
>>>> +						p_tsadc_data->passive_delay,
>>>> +						p_tsadc_data->polling_delay);
>>>> +
>>>> +	if (IS_ERR(data->tz)) {
>>>> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
>>>> +		goto fail_cpufreq_register;
>>>> +	}
>>>> +
>>>> +	if (p_tsadc_data->irq_en) {
>>>> +		data->irq = platform_get_irq(pdev, 0);
>>>> +		if (data->irq < 0) {
>>>> +			dev_err(&pdev->dev, "no irq resource?\n");
>>>> +			goto fail_irq;
>>>> +		}
>>>> +
>>>> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
>>>> +				rockchip_thermal_alarm_irq_thread,
>>>> +				IRQF_ONESHOT, "rockchip_thermal", data);
>>>> +		if (ret < 0) {
>>>> +			dev_err(&pdev->dev,
>>>> +				"failed to request tsadc irq: %d\n", ret);
>>>> +			goto fail_thermal_unregister;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	rockchip_thermal_initialize(data);
>>>> +	rockchip_thermal_control(data, true);
>>>> +
>>>> +	return 0;
>>>> +
>>>> +fail_thermal_unregister:
>>>> +	thermal_zone_device_unregister(data->tz);
>>>> +fail_irq:
>>>> +fail_cpufreq_register:
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +disable_clk:
>>>> +err_pclk:
>>>> +	clk_disable_unprepare(data->pclk);
>>>> +err_clk:
>>>> +	clk_disable_unprepare(data->clk);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_control(data, false);
>>>> +
>>>> +	thermal_zone_device_unregister(data->tz);
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +
>>> The above call is duplicated.
>> OK.
>>>> +	clk_disable_unprepare(data->clk);
>>>> +	clk_disable_unprepare(data->pclk);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int rockchip_thermal_suspend(struct device *dev)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_control(data, false);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_resume(struct device *dev)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_initialize(data);
>>>> +	rockchip_thermal_control(data, true);
>>>> +
>>>> +	return 0;
>>>> +}
>>> Would you need to manage your clocks too in the suspend resume path
>>> (data->clk and data->pclk)?
>> yes.
>> Usually,it's need disable to save power.
> Yes, that's my point. Please consider handling clocks to improve power
> savings.
>
>>>> +#endif
>>>> +
>>>> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
>>>> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
>>>> +
>>>> +static struct platform_driver rockchip_thermal_driver = {
>>>> +	.driver = {
>>>> +		   .name = "rockchip-thermal",
>>>> +		   .owner = THIS_MODULE,
>>>> +		   .pm = &rockchip_thermal_pm_ops,
>>>> +		   .of_match_table = of_rockchip_thermal_match,
>>>> +		   },
>>>> +	.probe = rockchip_thermal_probe,
>>>> +	.remove = rockchip_thermal_remove,
>>>> +};
>>>> +
>>>> +module_platform_driver(rockchip_thermal_driver);
>>>> +
>>>> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
>>>> +MODULE_AUTHOR("Rockchip, Inc.");
>>>> +MODULE_LICENSE("GPL");
>>> Your file header states GPL version two. Thus I suppose you meant:
>>> +MODULE_LICENSE("GPL v2");
>>>
>>> right?
>>>
>>> Check include/linux/module.h for further clarifications.
>> But I think the  "GPL"  is support for thr GNU Public License v2 or later.
> Exactly, if you intend to support v3, then it is fine. But your code
> header states only V2.
>
>> I will fix GPL v2 if I get it wrong.
> If your license is GPLv2 only as mentioned in your header, please use 'GPL
> v2' tag.
>
> Cheers,
>
>>>> +MODULE_ALIAS("platform:rockchip-thermal");
>>>> -- 
>>>> 1.9.1
>>>>
>>>>
>>> BR,
>>>
>>> Eduardo Valentin
>>>
>>>
>>>
>> -- 
>> Best regards,
>> Caesar
>>
>>
>
>

-- 
Best regards,
Caesar


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 1/4] thermal: rockchip: add driver for thermal
@ 2014-09-10 13:21           ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-10 13:21 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Eduardo,

? 2014/9/10 20:46, Eduardo Valentin ??:
> Hello Caesar,
>
> On Wed, Sep 10, 2014 at 12:39:07PM +0800, Caesar Wang wrote:
>> Dear Eduardo,
>>
>> I'm  sorry for it.
>> I just received this message.Maybe my mailbox has a problem.
>
> No problems. You can take your time.
>
>> Thank you for your comments.
>>
>> ? 2014?08?31? 04:09, Eduardo Valentin ??:
>>> Hello Ceasar,
>>>
>>> On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
>>>> Thermal is TS-ADC Controller module supports
>>>> user-defined mode and automatic mode.
>>>>
>>>> User-defined mode refers,TSADC all the control signals entirely by
>>>> software writing to register for direct control.
>>>>
>>>> Automaic mode refers to the module automatically poll TSADC output,
>>>> and the results were checked.If you find that the temperature High
>>>> in a period of time,an interrupt is generated to the processor
>>>> down-measures taken;if the temperature over a period of time High,
>>>> the resulting TSHUT gave CRU module,let it reset the entire chip,
>>>> or via GPIO give PMIC.
>>>>
>>>> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> I forgot to ask, is zhaoyifeng the correct name or is it a nickname?
:zhaoyifeng is chinese pinyin,Maybe I can correct name :Zhao Yi Feng or 
give him a English name:-D .

But his name is zhaoyifeng, so....
>>>> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>>>> ---
>>>>    drivers/thermal/Kconfig            |   9 +
>>>>    drivers/thermal/Makefile           |   1 +
>>>>    drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
>>>>    3 files changed, 679 insertions(+)
>>>>    create mode 100644 drivers/thermal/rockchip_thermal.c
>>>>
>>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>>> index f9a1386..a00aa1e 100644
>>>> --- a/drivers/thermal/Kconfig
>>>> +++ b/drivers/thermal/Kconfig
>>>> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
>>>>    	  Enable this to plug the SPEAr thermal sensor driver into the Linux
>>>>    	  thermal framework.
>>>>    
>>>> +config ROCKCHIP_THERMAL
>>>> +	tristate "Rockchip thermal driver"
>>>> +	depends on ARCH_ROCKCHIP
>>>> +	help
>>>> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
>>>> +	  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 RCAR_THERMAL
>>>>    	tristate "Renesas R-Car thermal driver"
>>>>    	depends on ARCH_SHMOBILE || COMPILE_TEST
>>>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>>>> index de0636a..b48b817 100644
>>>> --- a/drivers/thermal/Makefile
>>>> +++ b/drivers/thermal/Makefile
>>>> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
>>>>    
>>>>    # platform thermal drivers
>>>>    obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
>>>> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
>>>>    obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
>>>>    obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
>>>>    obj-y				+= samsung/
>>>> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
>>>> new file mode 100644
>>>> index 0000000..011f387
>>>> --- /dev/null
>>>> +++ b/drivers/thermal/rockchip_thermal.c
>>>> @@ -0,0 +1,669 @@
>>>> +/*
>>>> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
>>>> + *
>>>> + * 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/clk.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/of_irq.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/regulator/consumer.h>
>>>> +#include <linux/cpu_cooling.h>
>>>> +#include "thermal_core.h"
>>> Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
>>> sufficient?
>>>
>> yes, I will use linux/thermal.h.
>>>> +
>>>> +enum rockchip_thermal_trip {
>>>> +	ROCKCHIP_TRIP_PASSIVE,
>>>> +	ROCKCHIP_TRIP_CRITICAL,
>>>> +	ROCKCHIP_TRIP_NUM,
>>>> +};
>>>> +
>>> Why do you need your own trip types?
>>>
>>>> +struct rockchip_thermal_data {
>>>> +	const struct rockchip_tsadc_platform_data *pdata;
>>>> +	struct thermal_zone_device *tz;
>>>> +	struct thermal_cooling_device *cdev;
>>>> +	enum thermal_device_mode mode;
>>>> +	void __iomem *regs;
>>>> +
>>>> +	signed long temp_passive;
>>>> +	signed long temp_critical;
>>>> +	signed long temp_force_shut;
>>>> +	signed long alarm_temp;
>>>> +	signed long last_temp;
>>>> +	bool irq_enabled;
>>>> +	int irq;
>>>> +	struct clk *clk;
>>>> +	struct clk *pclk;
>>>> +};
>>>> +
>>>> +struct rockchip_tsadc_platform_data {
>>>> +	u8 irq_en;
>>>> +	signed long temp_passive;
>>>> +	signed long temp_critical;
>>>> +	signed long temp_force_shut;
>>>> +	int passive_delay;
>>>> +	int polling_delay;
>>>> +
>>>> +	int (*irq_handle)(void __iomem *reg);
>>>> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
>>>> +	int (*control)(void __iomem *reg, bool on);
>>>> +	u32 (*code_to_temp)(int temp);
>>>> +	u32 (*temp_to_code)(int temp);
>>>> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
>>>> +};
>>>> +
>>>> +/*TSADC V2 Sensor info define:*/
>>>> +#define TSADCV2_AUTO_CON			0x04
>>>> +#define TSADCV2_INT_EN				0x08
>>>> +#define TSADCV2_INT_PD				0x0c
>>>> +#define TSADCV2_DATA1				0x24
>>>> +#define TSADCV2_COMP1_INT			0x34
>>>> +#define TSADCV2_COMP1_SHUT			0x44
>>>> +#define TSADCV2_AUTO_PERIOD			0x68
>>>> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
>>>> +
>>>> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
>>>> +#define TSADCV2_AUTO_EN				(1 << 0)
>>>> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
>>>> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
>>>> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
>>>> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
>>>> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
>>>> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
>>>> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
>>>> +
>>> The above bits can be defined with BIT() macro, right?
>> Yes. The Bit() will be more resonable..
>>>    Something like:
>>> +#define TSADCV2_INT_SRC1_STATUS			BIT(1)
>>>
>>>
>>>> +#define TSADCV2_DATA_MASK			0xfff
>>>> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
>>>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
>>>> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
>>>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
>>>> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
>>>> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
>>>> +
>>>> +struct tsadc_table {
>>>> +	int code;
>>>> +	int temp;
>>>> +};
>>>> +
>>>> +static const struct tsadc_table v2_code_table[] = {
>>>> +	{TSADCV2_DATA_MASK, -40},
>>>> +	{3800, -40},
>>>> +	{3792, -35},
>>>> +	{3783, -30},
>>>> +	{3774, -25},
>>>> +	{3765, -20},
>>>> +	{3756, -15},
>>>> +	{3747, -10},
>>>> +	{3737, -5},
>>>> +	{3728, 0},
>>>> +	{3718, 5},
>>>> +	{3708, 10},
>>>> +	{3698, 15},
>>>> +	{3688, 20},
>>>> +	{3678, 25},
>>>> +	{3667, 30},
>>>> +	{3656, 35},
>>>> +	{3645, 40},
>>>> +	{3634, 45},
>>>> +	{3623, 50},
>>>> +	{3611, 55},
>>>> +	{3600, 60},
>>>> +	{3588, 65},
>>>> +	{3575, 70},
>>>> +	{3563, 75},
>>>> +	{3550, 80},
>>>> +	{3537, 85},
>>>> +	{3524, 90},
>>>> +	{3510, 95},
>>>> +	{3496, 100},
>>>> +	{3482, 105},
>>>> +	{3467, 110},
>>>> +	{3452, 115},
>>>> +	{3437, 120},
>>>> +	{3421, 125},
>>>> +	{0, 125},
>>>> +};
>>>> +
>>>> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
>>>> +{
>>>> +	u32 val;
>>>> +
>>>> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
>>>> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
>>> Why do you need to clear bit 8? Why hardcoded?
>> The bit 8 set 0 to clear the interrupt.
>>
> Would it make sense to create a macro for this?

OK .
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static u32 rk_tsadcv2_temp_to_code(int temp)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>>>> +		if (temp <= v2_code_table[i].temp && temp >
>>>> +		    v2_code_table[i - 1].temp)
>>>> +			return v2_code_table[i].code;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static u32 rk_tsadcv2_code_to_temp(int code)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>>>> +		if (code <= v2_code_table[i].code && code >
>>>> +		    v2_code_table[i + 1].code){
>>>> +			return v2_code_table[i].temp;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> I know the table is not something too big, but considering it is ordered
>>> by either ADC value code or by temp, at least one of the above searching function
>>> may be more efficient, right?
>> Yes, use the point will be more efficient.
>>>> +
>>>> +static int rk_tsadcv2_initialize(void __iomem *regs,
>>>> +				 signed long temp_force_shut)
>>>> +{
>>>> +	int shutdown_value;
>>>> +
>>>> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
>>>> +	/* Enable measurements at ~ 10 Hz */
>>> Does it leave the sampling clock at 10Hz?
>> yes.
> ok
>
>
>>> Is this clock exposed via
>>> clock framework?
>> The clock is divided by data->clk.
> ok
>
>>>> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
>>>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
>>>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
>>>> +		       TSADCV2_AUTO_PERIOD_HT);
>>>> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
>>>> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
>>>> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
>>>> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
>>>> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
>>>> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
>>>> +		       TSADCV2_INT_EN);
>>>> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
>>>> +		       TSADCV2_AUTO_CON);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
>>>> +{
>>>> +	u32 val;
>>>> +
>>>> +	if (on) {
>>>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>>>> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
>>>> +	} else {
>>>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>>>> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
>>>> +			       regs + TSADCV2_AUTO_CON);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
>>>> +{
>>>> +	int alarm_value;
>>>> +
>>>> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
>>>> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
>>>> +}
>>>> +
>>>> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
>>>> +	.irq_en = 1,
>>>> +	.temp_passive = 85000,
>>>> +	.temp_critical = 100000,
>>>> +	.temp_force_shut = 120000,
>>>> +	.passive_delay = 2000,
>>>> +	.polling_delay = 1000,
>>>> +	.irq_handle = rk_tsadcv2_irq_handle,
>>>> +	.initialize = rk_tsadcv2_initialize,
>>>> +	.control = rk_tsadcv2_control,
>>>> +	.code_to_temp = rk_tsadcv2_code_to_temp,
>>>> +	.temp_to_code = rk_tsadcv2_temp_to_code,
>>>> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
>>>> +};
>>> shall the above struct be also static?
>> OK.
>>>> +
>>>> +static const struct of_device_id of_rockchip_thermal_match[] = {
>>>> +	{
>>>> +		.compatible = "rockchip,rk3288-tsadc",
>>>> +		.data = (void *)&rk3288_tsadc_data,
>>>> +	},
>>>> +	{ /* end */ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
>>>> +
>>>> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
>>>> +				    signed long alarm_temp)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	data->alarm_temp = alarm_temp;
>>>> +	if (p_tsadc_data->set_alarm_temp)
>>>> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
>>>> +}
>>>> +
>>>> +static int rockchip_get_temp(struct thermal_zone_device *tz,
>>>> +			     unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +	u32 val;
>>>> +
>>>> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
>>>> +	*temp = p_tsadc_data->code_to_temp(val);
>>>> +
>>>> +	/* Update alarm value to next higher trip point */
>>>> +	if (data->alarm_temp == data->temp_passive && *temp >=
>>>> +	    data->temp_passive)
>>>> +		rockchip_set_alarm_temp(data, data->temp_critical);
>>>> +
>>>> +	if (data->alarm_temp == data->temp_critical && *temp <
>>>> +	    data->temp_passive) {
>>>> +		rockchip_set_alarm_temp(data, data->temp_passive);
>>>> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
>>>> +			data->alarm_temp / 1000);
>>>> +	}
>>>> +
>>>> +	if (*temp != data->last_temp) {
>>>> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
>>>> +		data->last_temp = *temp;
>>>> +	}
>>>> +
>>>> +	/* Reenable alarm IRQ if temperature below alarm temperature */
>>>> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
>>>> +		data->irq_enabled = true;
>>>> +		enable_irq(data->irq);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (p_tsadc_data->initialize)
>>>> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
>>>> +	rockchip_set_alarm_temp(data, data->temp_passive);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
>>>> +				     bool on)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (p_tsadc_data->control)
>>>> +		p_tsadc_data->control(data->regs, on);
>>>> +
>>>> +	if (on) {
>>>> +		data->irq_enabled = true;
>>>> +		data->mode = THERMAL_DEVICE_ENABLED;
>>>> +	} else {
>>>> +		data->irq_enabled = false;
>>>> +		data->mode = THERMAL_DEVICE_DISABLED;
>>>> +	}
>>>> +}
>>>> +
>>>> +static int rockchip_get_mode(struct thermal_zone_device *tz,
>>>> +			     enum thermal_device_mode *mode)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*mode = data->mode;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_set_mode(struct thermal_zone_device *tz,
>>>> +			     enum thermal_device_mode mode)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (mode == THERMAL_DEVICE_ENABLED) {
>>>> +		tz->polling_delay = p_tsadc_data->polling_delay;
>>>> +		tz->passive_delay = p_tsadc_data->passive_delay;
>>>> +		if (!data->irq_enabled) {
>>>> +			data->irq_enabled = true;
>>>> +			enable_irq(data->irq);
>>>> +		}
>>>> +	} else {
>>>> +		tz->polling_delay = 0;
>>>> +		tz->passive_delay = 0;
>>>> +		if (data->irq_enabled) {
>>>> +			disable_irq(data->irq);
>>>> +			data->irq_enabled = false;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	data->mode = mode;
>>>> +	thermal_zone_device_update(tz);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
>>>> +				  enum thermal_trip_type *type)
>>>> +{
>>>> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
>>>> +		 THERMAL_TRIP_CRITICAL;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
>>>> +				  unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*temp = data->temp_critical;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
>>>> +				  unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
>>>> +		 data->temp_critical;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
>>>> +				  unsigned long temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
>>>> +		return -EPERM;
>>>> +
>>>> +	data->temp_passive = temp;
>>>> +	rockchip_set_alarm_temp(data, temp);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_bind(struct thermal_zone_device *tz,
>>>> +			 struct thermal_cooling_device *cdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
>>>> +					       THERMAL_NO_LIMIT,
>>>> +					       THERMAL_NO_LIMIT);
>>>> +	if (ret) {
>>>> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>>>> +			tz->type, cdev->type, ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_unbind(struct thermal_zone_device *tz,
>>>> +			   struct thermal_cooling_device *cdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = thermal_zone_unbind_cooling_device(tz,
>>>> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
>>>> +	if (ret) {
>>>> +		dev_err(&tz->device,
>>>> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
>>>> +			cdev->type, ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> The method of binding and unbinding used above requires you to check if
>>> you are binding to the right cdev. If in your system you register more
>>> than one cdev, say someone loads the power supply core, which in turns
>>> register a cooling device for charging, your thermal zone will bind it
>>> to TRIP_PASSIVE. It will happen to any cooling device that eventually
>>> gets registered to the thermal framework. Is that the desired outcome?
>> Yes,I will use the generic trip points in the dts and fix it in the
>> thermal driver.
> great
>
>>> If not, you may want to compare the paramenter cdev to your data->cdev.
>>>
>>>> +
>>>> +static struct thermal_zone_device_ops rockchip_tz_ops = {
>>>> +	.bind = rockchip_bind,
>>>> +	.unbind = rockchip_unbind,
>>>> +	.get_temp = rockchip_get_temp,
>>>> +	.get_mode = rockchip_get_mode,
>>>> +	.set_mode = rockchip_set_mode,
>>>> +	.get_trip_type = rockchip_get_trip_type,
>>>> +	.get_trip_temp = rockchip_get_trip_temp,
>>>> +	.get_crit_temp = rockchip_get_crit_temp,
>>>> +	.set_trip_temp = rockchip_set_trip_temp,
>>>> +};
>>>> +
>>>> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = data;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
>>>> +		data->alarm_temp / 1000);
>>>> +
>>>> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
>>>> +		p_tsadc_data->irq_handle(data->regs);
>>>> +
>>>> +	thermal_zone_device_update(data->tz);
>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_probe(struct platform_device *pdev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
>>>> +	struct cpumask clip_cpus;
>>>> +	struct resource *res;
>>>> +	const struct of_device_id *match;
>>>> +	int ret, temp;
>>>> +
>>>> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
>>>> +			    GFP_KERNEL);
>>>> +	if (!data)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
>>>> +	if (IS_ERR(data->regs)) {
>>>> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
>>>> +			data->regs);
>>>> +		return PTR_ERR(data->regs);
>>>> +	}
>>>> +
>>>> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
>>>> +	if (!match)
>>>> +		return -ENXIO;
>>>> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
>>>> +	if (!data->pdata)
>>>> +		return -EINVAL;
>>>> +	p_tsadc_data = data->pdata;
>>>> +
>>>> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
>>>> +	if (IS_ERR(data->clk)) {
>>>> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
>>>> +		return PTR_ERR(data->clk);
>>>> +	}
>>>> +
>>>> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
>>>> +	if (IS_ERR(data->pclk)) {
>>>> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
>>>> +		return PTR_ERR(data->pclk);
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	* Use a default of 10KHz for the converter clock.
>>>> +	* This may become user-configurable in the future.
>>>> +	*/
>>>> +	ret = clk_set_rate(data->clk, 10000);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(data->clk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
>>>> +		goto err_clk;
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(data->pclk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to enable pclk\n");
>>>> +		goto err_pclk;
>>>> +	}
>>>> +
>>>> +	platform_set_drvdata(pdev, data);
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default passive temp property in the DT.\n");
>>>> +		data->temp_passive = p_tsadc_data->temp_passive;
>>>> +	} else {
>>>> +		data->temp_passive = temp;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default critical temp property in the DT.\n");
>>>> +		data->temp_critical = p_tsadc_data->temp_critical;
>>>> +	} else {
>>>> +		data->temp_critical = temp;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default force shut down temp property in the DT.\n");
>>>> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
>>>> +	} else {
>>>> +		data->temp_force_shut = temp;
>>>> +	}
>>>> +
>>>> +	cpumask_set_cpu(0, &clip_cpus);
>>>> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
>>>> +	if (IS_ERR(data->cdev)) {
>>>> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
>>>> +		goto disable_clk;
>>>> +	}
>>>> +
>>>> +	data->tz = thermal_zone_device_register("rockchip_thermal",
>>>> +						ROCKCHIP_TRIP_NUM,
>>>> +						0, data,
>>>> +						&rockchip_tz_ops, NULL,
>>>> +						p_tsadc_data->passive_delay,
>>>> +						p_tsadc_data->polling_delay);
>>>> +
>>>> +	if (IS_ERR(data->tz)) {
>>>> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
>>>> +		goto fail_cpufreq_register;
>>>> +	}
>>>> +
>>>> +	if (p_tsadc_data->irq_en) {
>>>> +		data->irq = platform_get_irq(pdev, 0);
>>>> +		if (data->irq < 0) {
>>>> +			dev_err(&pdev->dev, "no irq resource?\n");
>>>> +			goto fail_irq;
>>>> +		}
>>>> +
>>>> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
>>>> +				rockchip_thermal_alarm_irq_thread,
>>>> +				IRQF_ONESHOT, "rockchip_thermal", data);
>>>> +		if (ret < 0) {
>>>> +			dev_err(&pdev->dev,
>>>> +				"failed to request tsadc irq: %d\n", ret);
>>>> +			goto fail_thermal_unregister;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	rockchip_thermal_initialize(data);
>>>> +	rockchip_thermal_control(data, true);
>>>> +
>>>> +	return 0;
>>>> +
>>>> +fail_thermal_unregister:
>>>> +	thermal_zone_device_unregister(data->tz);
>>>> +fail_irq:
>>>> +fail_cpufreq_register:
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +disable_clk:
>>>> +err_pclk:
>>>> +	clk_disable_unprepare(data->pclk);
>>>> +err_clk:
>>>> +	clk_disable_unprepare(data->clk);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_control(data, false);
>>>> +
>>>> +	thermal_zone_device_unregister(data->tz);
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +
>>> The above call is duplicated.
>> OK.
>>>> +	clk_disable_unprepare(data->clk);
>>>> +	clk_disable_unprepare(data->pclk);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int rockchip_thermal_suspend(struct device *dev)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_control(data, false);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_resume(struct device *dev)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_initialize(data);
>>>> +	rockchip_thermal_control(data, true);
>>>> +
>>>> +	return 0;
>>>> +}
>>> Would you need to manage your clocks too in the suspend resume path
>>> (data->clk and data->pclk)?
>> yes.
>> Usually,it's need disable to save power.
> Yes, that's my point. Please consider handling clocks to improve power
> savings.
>
>>>> +#endif
>>>> +
>>>> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
>>>> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
>>>> +
>>>> +static struct platform_driver rockchip_thermal_driver = {
>>>> +	.driver = {
>>>> +		   .name = "rockchip-thermal",
>>>> +		   .owner = THIS_MODULE,
>>>> +		   .pm = &rockchip_thermal_pm_ops,
>>>> +		   .of_match_table = of_rockchip_thermal_match,
>>>> +		   },
>>>> +	.probe = rockchip_thermal_probe,
>>>> +	.remove = rockchip_thermal_remove,
>>>> +};
>>>> +
>>>> +module_platform_driver(rockchip_thermal_driver);
>>>> +
>>>> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
>>>> +MODULE_AUTHOR("Rockchip, Inc.");
>>>> +MODULE_LICENSE("GPL");
>>> Your file header states GPL version two. Thus I suppose you meant:
>>> +MODULE_LICENSE("GPL v2");
>>>
>>> right?
>>>
>>> Check include/linux/module.h for further clarifications.
>> But I think the  "GPL"  is support for thr GNU Public License v2 or later.
> Exactly, if you intend to support v3, then it is fine. But your code
> header states only V2.
>
>> I will fix GPL v2 if I get it wrong.
> If your license is GPLv2 only as mentioned in your header, please use 'GPL
> v2' tag.
>
> Cheers,
>
>>>> +MODULE_ALIAS("platform:rockchip-thermal");
>>>> -- 
>>>> 1.9.1
>>>>
>>>>
>>> BR,
>>>
>>> Eduardo Valentin
>>>
>>>
>>>
>> -- 
>> Best regards,
>> Caesar
>>
>>
>
>

-- 
Best regards,
Caesar

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-10  7:24                   ` Heiko Stübner
  (?)
@ 2014-09-11  2:36                     ` Zhang Rui
  -1 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-11  2:36 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: edubezval, Caesar Wang, LKML, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, Tao Huang, Eddie Cai, Douglas Anderson,
	dtor, Chris Zhong, addy.ke, Dmitry Torokhov, zhaoyifeng

On Wed, 2014-09-10 at 09:24 +0200, Heiko Stübner wrote:
> Am Dienstag, 9. September 2014, 21:14:18 schrieb edubezval@gmail.com:
> > Hello,
> > 
> > On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang@intel.com> wrote:
> > > On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> > >> Hello
> > >> 
> > >> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko Stübner wrote:
> > >> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > >> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > >> > > > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> > >> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > >> > > > >> This add the necessary binding documentation for the thermal
> > >> > > > >> found on Rockchip SoCs
> > >> > > > >> 
> > >> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > >> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > >> > > > >> ---
> > >> > > > >> 
> > >> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > >> > > > >> 
> > >> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > >> > > > >> 
> > >> > > > >>   create mode 100644
> > >> > > > >> 
> > >> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> > > > >> 
> > >> > > > >> diff --git
> > >> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> > > > >> new
> > >> > > > >> file
> > >> > > > >> mode 100644
> > >> > > > >> index 0000000..1ed4d4c
> > >> > > > >> --- /dev/null
> > >> > > > >> +++
> > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.tx
> > >> > > > >> t
> > >> > > > >> @@ -0,0 +1,20 @@
> > >> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > >> > > > >> +
> > >> > > > >> +Required properties:
> > >> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> > >> > > > >> +- reg: physical base address of the controller and length of
> > >> > > > >> memory
> > >> > > > >> mapped
> > >> > > > >> +       region.
> > >> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt
> > >> > > > >> specifier
> > >> > > > >> format +           depends on the interrupt controller.
> > >> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > >> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > >> > > > >> "apb_pclk" for +            the peripheral clock.
> > >> > > > > 
> > >> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> > >> > > > > properties in your driver without declaring them here.
> > >> > > > 
> > >> > > > frankly,the about are need be declared. but  there are 4 types[0]
> > >> > > > for
> > >> > > > trip in thermal framework,
> > >> > > > there is no force-shut for me. So I want to change it three
> > >> > > > additional
> > >> > > > properties in [PATCH V4 4/4],
> > >> > > > 
> > >> > > > 
> > >> > > > [0]
> > >> > > > {
> > >> > > > 
> > >> > > >      THERMAL_TRIP_CRITICAL,
> > >> > > >      THERMAL_TRIP_HOT,
> > >> > > >      THERMAL_TRIP_PASSIVE,
> > >> > > >      THERMAL_TRIP_ACTIVE,
> > >> > > > 
> > >> > > > }
> > >> > > 
> > >> > > this sounds reasonable to me.
> > >> > > 
> > >> > > > > But more importantly, please use the generic trip-points for
> > >> > > > > this. I
> > >> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > >> > > > > trippoint [0] for the additional trip-point you have - thermal
> > >> > > > > maintainers, please shout if I'm wrong :-)
> > >> > > 
> > >> > > what is the difference between a critical trip point and a
> > >> > > "forced-shutdown" trip point?
> > >> > > Thermal core will do a shutdown in case the critical trip point is
> > >> > > triggered.
> > >> > 
> > >> > The forced-shutdown is where the thermal controller is supposed to also
> > >> > do a>> 
> > >> Currently, there is no discrimination between hardware configured /
> > >> triggered thermal shutdown and software detected / triggered thermal
> > >> shutdown. One way to implement it though is to reuse the critical trip
> > >> type. Even if you use more than one trip type it is doable, it will
> > >> depend on the priorities you give to software triggered and hardware
> > >> triggered.
> > >> 
> > >> > shutdown in hardware. As you said the thermal core will also shutdown
> > >> > at the critical trip point, I guess we could map Caesar's value like
> > >> > 
> > >> > trip-point          tsadc
> > >> > critical            forced-shutdown (the 120 degrees in patch 4)
> > >> > 
> > >> > hot                 critical (the 100 degrees)
> > >> > ...
> > >> 
> > >> In the case we are planing to expand the trip type range, adding one
> > >> specific to hardware configurable shutdown makes sense to me too.
> > > 
> > > hmmm, why? you don't want an orderly shutdown? I still do not understand
> > > why we need a hardware shutdown trip point.
> > > Say, if we expect the system to be shutdown at 100C, I don't think we
> > > have a chance to trigger the hardware shutdown trip point.
> > > Further more, if my understanding is right, thermal core won't do
> > > anything for the hardware shutdown trip point because the system will be
> > > shutdown automatically, right? If this is true, why bother introducing
> > > this to thermal core?
> > 
> > Some ICs allow configuring the temperature when the shutdown will
> > happen. That is, you setup in registers the thermal shutdown
> > threshold, and one of the output pin of the IC is wired to, say, the
> > processor reset pin. Some other ICs have the threshold hardwired, and
> > cannot be configured.
> > 
> > Those options are a last chance to avoid processors to burn, in case
> > software really gets stuck at high temperatures.
> > 
> > The only thing that the thermal driver would need to worry is the
> > configuration step, that is, writing the value to the registers. In
> > the case the thermal core would have a specific trip type for such
> > case, the core itself would not do anything, except allowing designing
> > a thermal zone with hardware shutdown trips. And thus the thermal
> > driver would do the configuration.
> > 
> > 
> > Currently, the way I see to implement this is to interpret critical
> > trips as the threshold to be configured at the IC registers. That is,
> > reusing critical trips as orderly power down and as the hardware
> > shutdown threshold.
> 
> which was what I also meant to express above [but seemingly failed to do 
> properly :-) ].
> 
> Critical is specified as "Hardware not reliable", so I'd think it wouldn't 
> matter how the hw is shut down (orderly/unorderly) as long as its done.

Hmmm,

As what we want is to make thermal driver have a chance to configure the
hardware shutdown registers, I'm thinking if we can do this without
representing the hardware shutdown value as a trip point.
Say,
1. parse DT, and get the hardware shutdown temperature value, and store
it somewhere, e.g. struct __thermal_zone.
2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
in thermal_zone_of_sensor_register().
3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
thermal_zone_of_sensor_register().

thanks,
rui


^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-11  2:36                     ` Zhang Rui
  0 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-11  2:36 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: edubezval, Caesar Wang, LKML, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, Tao Huang, Eddie Cai, Douglas Anderson,
	dtor, Chris Zhong, addy.ke, Dmitry Torokhov, zhaoyifeng

On Wed, 2014-09-10 at 09:24 +0200, Heiko Stübner wrote:
> Am Dienstag, 9. September 2014, 21:14:18 schrieb edubezval@gmail.com:
> > Hello,
> > 
> > On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang@intel.com> wrote:
> > > On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> > >> Hello
> > >> 
> > >> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko Stübner wrote:
> > >> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > >> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > >> > > > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> > >> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > >> > > > >> This add the necessary binding documentation for the thermal
> > >> > > > >> found on Rockchip SoCs
> > >> > > > >> 
> > >> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > >> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > >> > > > >> ---
> > >> > > > >> 
> > >> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > >> > > > >> 
> > >> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > >> > > > >> 
> > >> > > > >>   create mode 100644
> > >> > > > >> 
> > >> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> > > > >> 
> > >> > > > >> diff --git
> > >> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> > > > >> new
> > >> > > > >> file
> > >> > > > >> mode 100644
> > >> > > > >> index 0000000..1ed4d4c
> > >> > > > >> --- /dev/null
> > >> > > > >> +++
> > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.tx
> > >> > > > >> t
> > >> > > > >> @@ -0,0 +1,20 @@
> > >> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > >> > > > >> +
> > >> > > > >> +Required properties:
> > >> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> > >> > > > >> +- reg: physical base address of the controller and length of
> > >> > > > >> memory
> > >> > > > >> mapped
> > >> > > > >> +       region.
> > >> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt
> > >> > > > >> specifier
> > >> > > > >> format +           depends on the interrupt controller.
> > >> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > >> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > >> > > > >> "apb_pclk" for +            the peripheral clock.
> > >> > > > > 
> > >> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> > >> > > > > properties in your driver without declaring them here.
> > >> > > > 
> > >> > > > frankly,the about are need be declared. but  there are 4 types[0]
> > >> > > > for
> > >> > > > trip in thermal framework,
> > >> > > > there is no force-shut for me. So I want to change it three
> > >> > > > additional
> > >> > > > properties in [PATCH V4 4/4],
> > >> > > > 
> > >> > > > 
> > >> > > > [0]
> > >> > > > {
> > >> > > > 
> > >> > > >      THERMAL_TRIP_CRITICAL,
> > >> > > >      THERMAL_TRIP_HOT,
> > >> > > >      THERMAL_TRIP_PASSIVE,
> > >> > > >      THERMAL_TRIP_ACTIVE,
> > >> > > > 
> > >> > > > }
> > >> > > 
> > >> > > this sounds reasonable to me.
> > >> > > 
> > >> > > > > But more importantly, please use the generic trip-points for
> > >> > > > > this. I
> > >> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > >> > > > > trippoint [0] for the additional trip-point you have - thermal
> > >> > > > > maintainers, please shout if I'm wrong :-)
> > >> > > 
> > >> > > what is the difference between a critical trip point and a
> > >> > > "forced-shutdown" trip point?
> > >> > > Thermal core will do a shutdown in case the critical trip point is
> > >> > > triggered.
> > >> > 
> > >> > The forced-shutdown is where the thermal controller is supposed to also
> > >> > do a>> 
> > >> Currently, there is no discrimination between hardware configured /
> > >> triggered thermal shutdown and software detected / triggered thermal
> > >> shutdown. One way to implement it though is to reuse the critical trip
> > >> type. Even if you use more than one trip type it is doable, it will
> > >> depend on the priorities you give to software triggered and hardware
> > >> triggered.
> > >> 
> > >> > shutdown in hardware. As you said the thermal core will also shutdown
> > >> > at the critical trip point, I guess we could map Caesar's value like
> > >> > 
> > >> > trip-point          tsadc
> > >> > critical            forced-shutdown (the 120 degrees in patch 4)
> > >> > 
> > >> > hot                 critical (the 100 degrees)
> > >> > ...
> > >> 
> > >> In the case we are planing to expand the trip type range, adding one
> > >> specific to hardware configurable shutdown makes sense to me too.
> > > 
> > > hmmm, why? you don't want an orderly shutdown? I still do not understand
> > > why we need a hardware shutdown trip point.
> > > Say, if we expect the system to be shutdown at 100C, I don't think we
> > > have a chance to trigger the hardware shutdown trip point.
> > > Further more, if my understanding is right, thermal core won't do
> > > anything for the hardware shutdown trip point because the system will be
> > > shutdown automatically, right? If this is true, why bother introducing
> > > this to thermal core?
> > 
> > Some ICs allow configuring the temperature when the shutdown will
> > happen. That is, you setup in registers the thermal shutdown
> > threshold, and one of the output pin of the IC is wired to, say, the
> > processor reset pin. Some other ICs have the threshold hardwired, and
> > cannot be configured.
> > 
> > Those options are a last chance to avoid processors to burn, in case
> > software really gets stuck at high temperatures.
> > 
> > The only thing that the thermal driver would need to worry is the
> > configuration step, that is, writing the value to the registers. In
> > the case the thermal core would have a specific trip type for such
> > case, the core itself would not do anything, except allowing designing
> > a thermal zone with hardware shutdown trips. And thus the thermal
> > driver would do the configuration.
> > 
> > 
> > Currently, the way I see to implement this is to interpret critical
> > trips as the threshold to be configured at the IC registers. That is,
> > reusing critical trips as orderly power down and as the hardware
> > shutdown threshold.
> 
> which was what I also meant to express above [but seemingly failed to do 
> properly :-) ].
> 
> Critical is specified as "Hardware not reliable", so I'd think it wouldn't 
> matter how the hw is shut down (orderly/unorderly) as long as its done.

Hmmm,

As what we want is to make thermal driver have a chance to configure the
hardware shutdown registers, I'm thinking if we can do this without
representing the hardware shutdown value as a trip point.
Say,
1. parse DT, and get the hardware shutdown temperature value, and store
it somewhere, e.g. struct __thermal_zone.
2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
in thermal_zone_of_sensor_register().
3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
thermal_zone_of_sensor_register().

thanks,
rui


^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-11  2:36                     ` Zhang Rui
  0 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-11  2:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2014-09-10 at 09:24 +0200, Heiko St?bner wrote:
> Am Dienstag, 9. September 2014, 21:14:18 schrieb edubezval at gmail.com:
> > Hello,
> > 
> > On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang@intel.com> wrote:
> > > On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> > >> Hello
> > >> 
> > >> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko St?bner wrote:
> > >> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > >> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > >> > > > ? 2014?09?03? 16:07, Heiko St?bner ??:
> > >> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > >> > > > >> This add the necessary binding documentation for the thermal
> > >> > > > >> found on Rockchip SoCs
> > >> > > > >> 
> > >> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > >> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > >> > > > >> ---
> > >> > > > >> 
> > >> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > >> > > > >> 
> > >> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > >> > > > >> 
> > >> > > > >>   create mode 100644
> > >> > > > >> 
> > >> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> > > > >> 
> > >> > > > >> diff --git
> > >> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > >> > > > >> new
> > >> > > > >> file
> > >> > > > >> mode 100644
> > >> > > > >> index 0000000..1ed4d4c
> > >> > > > >> --- /dev/null
> > >> > > > >> +++
> > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.tx
> > >> > > > >> t
> > >> > > > >> @@ -0,0 +1,20 @@
> > >> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > >> > > > >> +
> > >> > > > >> +Required properties:
> > >> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> > >> > > > >> +- reg: physical base address of the controller and length of
> > >> > > > >> memory
> > >> > > > >> mapped
> > >> > > > >> +       region.
> > >> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt
> > >> > > > >> specifier
> > >> > > > >> format +           depends on the interrupt controller.
> > >> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > >> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > >> > > > >> "apb_pclk" for +            the peripheral clock.
> > >> > > > > 
> > >> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> > >> > > > > properties in your driver without declaring them here.
> > >> > > > 
> > >> > > > frankly,the about are need be declared. but  there are 4 types[0]
> > >> > > > for
> > >> > > > trip in thermal framework,
> > >> > > > there is no force-shut for me. So I want to change it three
> > >> > > > additional
> > >> > > > properties in [PATCH V4 4/4],
> > >> > > > 
> > >> > > > 
> > >> > > > [0]
> > >> > > > {
> > >> > > > 
> > >> > > >      THERMAL_TRIP_CRITICAL,
> > >> > > >      THERMAL_TRIP_HOT,
> > >> > > >      THERMAL_TRIP_PASSIVE,
> > >> > > >      THERMAL_TRIP_ACTIVE,
> > >> > > > 
> > >> > > > }
> > >> > > 
> > >> > > this sounds reasonable to me.
> > >> > > 
> > >> > > > > But more importantly, please use the generic trip-points for
> > >> > > > > this. I
> > >> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > >> > > > > trippoint [0] for the additional trip-point you have - thermal
> > >> > > > > maintainers, please shout if I'm wrong :-)
> > >> > > 
> > >> > > what is the difference between a critical trip point and a
> > >> > > "forced-shutdown" trip point?
> > >> > > Thermal core will do a shutdown in case the critical trip point is
> > >> > > triggered.
> > >> > 
> > >> > The forced-shutdown is where the thermal controller is supposed to also
> > >> > do a>> 
> > >> Currently, there is no discrimination between hardware configured /
> > >> triggered thermal shutdown and software detected / triggered thermal
> > >> shutdown. One way to implement it though is to reuse the critical trip
> > >> type. Even if you use more than one trip type it is doable, it will
> > >> depend on the priorities you give to software triggered and hardware
> > >> triggered.
> > >> 
> > >> > shutdown in hardware. As you said the thermal core will also shutdown
> > >> > at the critical trip point, I guess we could map Caesar's value like
> > >> > 
> > >> > trip-point          tsadc
> > >> > critical            forced-shutdown (the 120 degrees in patch 4)
> > >> > 
> > >> > hot                 critical (the 100 degrees)
> > >> > ...
> > >> 
> > >> In the case we are planing to expand the trip type range, adding one
> > >> specific to hardware configurable shutdown makes sense to me too.
> > > 
> > > hmmm, why? you don't want an orderly shutdown? I still do not understand
> > > why we need a hardware shutdown trip point.
> > > Say, if we expect the system to be shutdown at 100C, I don't think we
> > > have a chance to trigger the hardware shutdown trip point.
> > > Further more, if my understanding is right, thermal core won't do
> > > anything for the hardware shutdown trip point because the system will be
> > > shutdown automatically, right? If this is true, why bother introducing
> > > this to thermal core?
> > 
> > Some ICs allow configuring the temperature when the shutdown will
> > happen. That is, you setup in registers the thermal shutdown
> > threshold, and one of the output pin of the IC is wired to, say, the
> > processor reset pin. Some other ICs have the threshold hardwired, and
> > cannot be configured.
> > 
> > Those options are a last chance to avoid processors to burn, in case
> > software really gets stuck at high temperatures.
> > 
> > The only thing that the thermal driver would need to worry is the
> > configuration step, that is, writing the value to the registers. In
> > the case the thermal core would have a specific trip type for such
> > case, the core itself would not do anything, except allowing designing
> > a thermal zone with hardware shutdown trips. And thus the thermal
> > driver would do the configuration.
> > 
> > 
> > Currently, the way I see to implement this is to interpret critical
> > trips as the threshold to be configured at the IC registers. That is,
> > reusing critical trips as orderly power down and as the hardware
> > shutdown threshold.
> 
> which was what I also meant to express above [but seemingly failed to do 
> properly :-) ].
> 
> Critical is specified as "Hardware not reliable", so I'd think it wouldn't 
> matter how the hw is shut down (orderly/unorderly) as long as its done.

Hmmm,

As what we want is to make thermal driver have a chance to configure the
hardware shutdown registers, I'm thinking if we can do this without
representing the hardware shutdown value as a trip point.
Say,
1. parse DT, and get the hardware shutdown temperature value, and store
it somewhere, e.g. struct __thermal_zone.
2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
in thermal_zone_of_sensor_register().
3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
thermal_zone_of_sensor_register().

thanks,
rui

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-11  2:36                     ` Zhang Rui
  (?)
@ 2014-09-11 12:18                       ` Eduardo Valentin
  -1 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-09-11 12:18 UTC (permalink / raw)
  To: Zhang Rui
  Cc: Heiko Stübner, Caesar Wang, LKML, linux-pm,
	linux-arm-kernel, devicetree, linux-doc, Tao Huang, Eddie Cai,
	Douglas Anderson, dtor, Chris Zhong, addy.ke, Dmitry Torokhov,
	zhaoyifeng

Hello Rui,

On Thu, Sep 11, 2014 at 10:36:52AM +0800, Zhang Rui wrote:
> On Wed, 2014-09-10 at 09:24 +0200, Heiko Stübner wrote:
> > Am Dienstag, 9. September 2014, 21:14:18 schrieb edubezval@gmail.com:
> > > Hello,
> > > 
> > > On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang@intel.com> wrote:
> > > > On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> > > >> Hello
> > > >> 
> > > >> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko Stübner wrote:
> > > >> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > > >> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > > >> > > > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> > > >> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > > >> > > > >> This add the necessary binding documentation for the thermal
> > > >> > > > >> found on Rockchip SoCs
> > > >> > > > >> 
> > > >> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > > >> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > > >> > > > >> ---
> > > >> > > > >> 
> > > >> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > > >> > > > >> 
> > > >> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > > >> > > > >> 
> > > >> > > > >>   create mode 100644
> > > >> > > > >> 
> > > >> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> > > > >> 
> > > >> > > > >> diff --git
> > > >> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> > > > >> new
> > > >> > > > >> file
> > > >> > > > >> mode 100644
> > > >> > > > >> index 0000000..1ed4d4c
> > > >> > > > >> --- /dev/null
> > > >> > > > >> +++
> > > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.tx
> > > >> > > > >> t
> > > >> > > > >> @@ -0,0 +1,20 @@
> > > >> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > > >> > > > >> +
> > > >> > > > >> +Required properties:
> > > >> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> > > >> > > > >> +- reg: physical base address of the controller and length of
> > > >> > > > >> memory
> > > >> > > > >> mapped
> > > >> > > > >> +       region.
> > > >> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt
> > > >> > > > >> specifier
> > > >> > > > >> format +           depends on the interrupt controller.
> > > >> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > > >> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > > >> > > > >> "apb_pclk" for +            the peripheral clock.
> > > >> > > > > 
> > > >> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> > > >> > > > > properties in your driver without declaring them here.
> > > >> > > > 
> > > >> > > > frankly,the about are need be declared. but  there are 4 types[0]
> > > >> > > > for
> > > >> > > > trip in thermal framework,
> > > >> > > > there is no force-shut for me. So I want to change it three
> > > >> > > > additional
> > > >> > > > properties in [PATCH V4 4/4],
> > > >> > > > 
> > > >> > > > 
> > > >> > > > [0]
> > > >> > > > {
> > > >> > > > 
> > > >> > > >      THERMAL_TRIP_CRITICAL,
> > > >> > > >      THERMAL_TRIP_HOT,
> > > >> > > >      THERMAL_TRIP_PASSIVE,
> > > >> > > >      THERMAL_TRIP_ACTIVE,
> > > >> > > > 
> > > >> > > > }
> > > >> > > 
> > > >> > > this sounds reasonable to me.
> > > >> > > 
> > > >> > > > > But more importantly, please use the generic trip-points for
> > > >> > > > > this. I
> > > >> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > >> > > > > trippoint [0] for the additional trip-point you have - thermal
> > > >> > > > > maintainers, please shout if I'm wrong :-)
> > > >> > > 
> > > >> > > what is the difference between a critical trip point and a
> > > >> > > "forced-shutdown" trip point?
> > > >> > > Thermal core will do a shutdown in case the critical trip point is
> > > >> > > triggered.
> > > >> > 
> > > >> > The forced-shutdown is where the thermal controller is supposed to also
> > > >> > do a>> 
> > > >> Currently, there is no discrimination between hardware configured /
> > > >> triggered thermal shutdown and software detected / triggered thermal
> > > >> shutdown. One way to implement it though is to reuse the critical trip
> > > >> type. Even if you use more than one trip type it is doable, it will
> > > >> depend on the priorities you give to software triggered and hardware
> > > >> triggered.
> > > >> 
> > > >> > shutdown in hardware. As you said the thermal core will also shutdown
> > > >> > at the critical trip point, I guess we could map Caesar's value like
> > > >> > 
> > > >> > trip-point          tsadc
> > > >> > critical            forced-shutdown (the 120 degrees in patch 4)
> > > >> > 
> > > >> > hot                 critical (the 100 degrees)
> > > >> > ...
> > > >> 
> > > >> In the case we are planing to expand the trip type range, adding one
> > > >> specific to hardware configurable shutdown makes sense to me too.
> > > > 
> > > > hmmm, why? you don't want an orderly shutdown? I still do not understand
> > > > why we need a hardware shutdown trip point.
> > > > Say, if we expect the system to be shutdown at 100C, I don't think we
> > > > have a chance to trigger the hardware shutdown trip point.
> > > > Further more, if my understanding is right, thermal core won't do
> > > > anything for the hardware shutdown trip point because the system will be
> > > > shutdown automatically, right? If this is true, why bother introducing
> > > > this to thermal core?
> > > 
> > > Some ICs allow configuring the temperature when the shutdown will
> > > happen. That is, you setup in registers the thermal shutdown
> > > threshold, and one of the output pin of the IC is wired to, say, the
> > > processor reset pin. Some other ICs have the threshold hardwired, and
> > > cannot be configured.
> > > 
> > > Those options are a last chance to avoid processors to burn, in case
> > > software really gets stuck at high temperatures.
> > > 
> > > The only thing that the thermal driver would need to worry is the
> > > configuration step, that is, writing the value to the registers. In
> > > the case the thermal core would have a specific trip type for such
> > > case, the core itself would not do anything, except allowing designing
> > > a thermal zone with hardware shutdown trips. And thus the thermal
> > > driver would do the configuration.
> > > 
> > > 
> > > Currently, the way I see to implement this is to interpret critical
> > > trips as the threshold to be configured at the IC registers. That is,
> > > reusing critical trips as orderly power down and as the hardware
> > > shutdown threshold.
> > 
> > which was what I also meant to express above [but seemingly failed to do 
> > properly :-) ].
> > 
> > Critical is specified as "Hardware not reliable", so I'd think it wouldn't 
> > matter how the hw is shut down (orderly/unorderly) as long as its done.
> 
> Hmmm,
> 
> As what we want is to make thermal driver have a chance to configure the
> hardware shutdown registers, I'm thinking if we can do this without
> representing the hardware shutdown value as a trip point.
> Say,
> 1. parse DT, and get the hardware shutdown temperature value, and store
> it somewhere, e.g. struct __thermal_zone.
> 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> in thermal_zone_of_sensor_register().
> 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> thermal_zone_of_sensor_register().


The only issue I have with the above proposal is that not all platforms
use DT. Some still boot with boardfiles, for instance. Thus, the
parameter to configure hardware thermal shutdown needs to be common on
thermal core, not specific to of-thermal. Do you agree?


> 
> thanks,
> rui
> 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-11 12:18                       ` Eduardo Valentin
  0 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-09-11 12:18 UTC (permalink / raw)
  To: Zhang Rui
  Cc: Heiko Stübner, Caesar Wang, LKML,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA, Tao Huang, Eddie Cai,
	Douglas Anderson, dtor, Chris Zhong,
	addy.ke-TNX95d0MmH7DzftRWevZcw, Dmitry Torokhov, zhaoyifeng

Hello Rui,

On Thu, Sep 11, 2014 at 10:36:52AM +0800, Zhang Rui wrote:
> On Wed, 2014-09-10 at 09:24 +0200, Heiko Stübner wrote:
> > Am Dienstag, 9. September 2014, 21:14:18 schrieb edubezval-Re5JQEeQqe8@public.gmane.orgm:
> > > Hello,
> > > 
> > > On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> wrote:
> > > > On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> > > >> Hello
> > > >> 
> > > >> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko Stübner wrote:
> > > >> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > > >> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > > >> > > > 在 2014年09月03日 16:07, Heiko Stübner 写道:
> > > >> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > > >> > > > >> This add the necessary binding documentation for the thermal
> > > >> > > > >> found on Rockchip SoCs
> > > >> > > > >> 
> > > >> > > > >> Signed-off-by: zhaoyifeng <zyf-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> > > >> > > > >> Signed-off-by: Caesar Wang <caesar.wang-TNX95d0MmH5qZ5pVbMyqKg@public.gmane.orgm>
> > > >> > > > >> ---
> > > >> > > > >> 
> > > >> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > > >> > > > >> 
> > > >> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > > >> > > > >> 
> > > >> > > > >>   create mode 100644
> > > >> > > > >> 
> > > >> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> > > > >> 
> > > >> > > > >> diff --git
> > > >> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> > > > >> new
> > > >> > > > >> file
> > > >> > > > >> mode 100644
> > > >> > > > >> index 0000000..1ed4d4c
> > > >> > > > >> --- /dev/null
> > > >> > > > >> +++
> > > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.tx
> > > >> > > > >> t
> > > >> > > > >> @@ -0,0 +1,20 @@
> > > >> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > > >> > > > >> +
> > > >> > > > >> +Required properties:
> > > >> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> > > >> > > > >> +- reg: physical base address of the controller and length of
> > > >> > > > >> memory
> > > >> > > > >> mapped
> > > >> > > > >> +       region.
> > > >> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt
> > > >> > > > >> specifier
> > > >> > > > >> format +           depends on the interrupt controller.
> > > >> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > > >> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > > >> > > > >> "apb_pclk" for +            the peripheral clock.
> > > >> > > > > 
> > > >> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> > > >> > > > > properties in your driver without declaring them here.
> > > >> > > > 
> > > >> > > > frankly,the about are need be declared. but  there are 4 types[0]
> > > >> > > > for
> > > >> > > > trip in thermal framework,
> > > >> > > > there is no force-shut for me. So I want to change it three
> > > >> > > > additional
> > > >> > > > properties in [PATCH V4 4/4],
> > > >> > > > 
> > > >> > > > 
> > > >> > > > [0]
> > > >> > > > {
> > > >> > > > 
> > > >> > > >      THERMAL_TRIP_CRITICAL,
> > > >> > > >      THERMAL_TRIP_HOT,
> > > >> > > >      THERMAL_TRIP_PASSIVE,
> > > >> > > >      THERMAL_TRIP_ACTIVE,
> > > >> > > > 
> > > >> > > > }
> > > >> > > 
> > > >> > > this sounds reasonable to me.
> > > >> > > 
> > > >> > > > > But more importantly, please use the generic trip-points for
> > > >> > > > > this. I
> > > >> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > >> > > > > trippoint [0] for the additional trip-point you have - thermal
> > > >> > > > > maintainers, please shout if I'm wrong :-)
> > > >> > > 
> > > >> > > what is the difference between a critical trip point and a
> > > >> > > "forced-shutdown" trip point?
> > > >> > > Thermal core will do a shutdown in case the critical trip point is
> > > >> > > triggered.
> > > >> > 
> > > >> > The forced-shutdown is where the thermal controller is supposed to also
> > > >> > do a>> 
> > > >> Currently, there is no discrimination between hardware configured /
> > > >> triggered thermal shutdown and software detected / triggered thermal
> > > >> shutdown. One way to implement it though is to reuse the critical trip
> > > >> type. Even if you use more than one trip type it is doable, it will
> > > >> depend on the priorities you give to software triggered and hardware
> > > >> triggered.
> > > >> 
> > > >> > shutdown in hardware. As you said the thermal core will also shutdown
> > > >> > at the critical trip point, I guess we could map Caesar's value like
> > > >> > 
> > > >> > trip-point          tsadc
> > > >> > critical            forced-shutdown (the 120 degrees in patch 4)
> > > >> > 
> > > >> > hot                 critical (the 100 degrees)
> > > >> > ...
> > > >> 
> > > >> In the case we are planing to expand the trip type range, adding one
> > > >> specific to hardware configurable shutdown makes sense to me too.
> > > > 
> > > > hmmm, why? you don't want an orderly shutdown? I still do not understand
> > > > why we need a hardware shutdown trip point.
> > > > Say, if we expect the system to be shutdown at 100C, I don't think we
> > > > have a chance to trigger the hardware shutdown trip point.
> > > > Further more, if my understanding is right, thermal core won't do
> > > > anything for the hardware shutdown trip point because the system will be
> > > > shutdown automatically, right? If this is true, why bother introducing
> > > > this to thermal core?
> > > 
> > > Some ICs allow configuring the temperature when the shutdown will
> > > happen. That is, you setup in registers the thermal shutdown
> > > threshold, and one of the output pin of the IC is wired to, say, the
> > > processor reset pin. Some other ICs have the threshold hardwired, and
> > > cannot be configured.
> > > 
> > > Those options are a last chance to avoid processors to burn, in case
> > > software really gets stuck at high temperatures.
> > > 
> > > The only thing that the thermal driver would need to worry is the
> > > configuration step, that is, writing the value to the registers. In
> > > the case the thermal core would have a specific trip type for such
> > > case, the core itself would not do anything, except allowing designing
> > > a thermal zone with hardware shutdown trips. And thus the thermal
> > > driver would do the configuration.
> > > 
> > > 
> > > Currently, the way I see to implement this is to interpret critical
> > > trips as the threshold to be configured at the IC registers. That is,
> > > reusing critical trips as orderly power down and as the hardware
> > > shutdown threshold.
> > 
> > which was what I also meant to express above [but seemingly failed to do 
> > properly :-) ].
> > 
> > Critical is specified as "Hardware not reliable", so I'd think it wouldn't 
> > matter how the hw is shut down (orderly/unorderly) as long as its done.
> 
> Hmmm,
> 
> As what we want is to make thermal driver have a chance to configure the
> hardware shutdown registers, I'm thinking if we can do this without
> representing the hardware shutdown value as a trip point.
> Say,
> 1. parse DT, and get the hardware shutdown temperature value, and store
> it somewhere, e.g. struct __thermal_zone.
> 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> in thermal_zone_of_sensor_register().
> 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> thermal_zone_of_sensor_register().


The only issue I have with the above proposal is that not all platforms
use DT. Some still boot with boardfiles, for instance. Thus, the
parameter to configure hardware thermal shutdown needs to be common on
thermal core, not specific to of-thermal. Do you agree?


> 
> thanks,
> rui
> 
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-11 12:18                       ` Eduardo Valentin
  0 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-09-11 12:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Rui,

On Thu, Sep 11, 2014 at 10:36:52AM +0800, Zhang Rui wrote:
> On Wed, 2014-09-10 at 09:24 +0200, Heiko St?bner wrote:
> > Am Dienstag, 9. September 2014, 21:14:18 schrieb edubezval at gmail.com:
> > > Hello,
> > > 
> > > On Tue, Sep 9, 2014 at 9:02 PM, Zhang Rui <rui.zhang@intel.com> wrote:
> > > > On Tue, 2014-09-09 at 11:09 -0400, Eduardo Valentin wrote:
> > > >> Hello
> > > >> 
> > > >> On Tue, Sep 09, 2014 at 01:35:31PM +0200, Heiko St?bner wrote:
> > > >> > Am Dienstag, 9. September 2014, 10:27:17 schrieb Zhang Rui:
> > > >> > > On Thu, 2014-09-04 at 09:02 +0800, Caesar Wang wrote:
> > > >> > > > ? 2014?09?03? 16:07, Heiko St?bner ??:
> > > >> > > > > Am Mittwoch, 3. September 2014, 10:10:37 schrieb Caesar Wang:
> > > >> > > > >> This add the necessary binding documentation for the thermal
> > > >> > > > >> found on Rockchip SoCs
> > > >> > > > >> 
> > > >> > > > >> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> > > >> > > > >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> > > >> > > > >> ---
> > > >> > > > >> 
> > > >> > > > >>   .../devicetree/bindings/thermal/rockchip-thermal.txt | 20
> > > >> > > > >> 
> > > >> > > > >> ++++++++++++++++++++ 1 file changed, 20 insertions(+)
> > > >> > > > >> 
> > > >> > > > >>   create mode 100644
> > > >> > > > >> 
> > > >> > > > >> Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> > > > >> 
> > > >> > > > >> diff --git
> > > >> > > > >> a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
> > > >> > > > >> new
> > > >> > > > >> file
> > > >> > > > >> mode 100644
> > > >> > > > >> index 0000000..1ed4d4c
> > > >> > > > >> --- /dev/null
> > > >> > > > >> +++
> > > >> > > > >> b/Documentation/devicetree/bindings/thermal/rockchip-thermal.tx
> > > >> > > > >> t
> > > >> > > > >> @@ -0,0 +1,20 @@
> > > >> > > > >> +* Temperature Sensor ADC (TSADC) on rockchip SoCs
> > > >> > > > >> +
> > > >> > > > >> +Required properties:
> > > >> > > > >> +- compatible: "rockchip,rk3288-tsadc"
> > > >> > > > >> +- reg: physical base address of the controller and length of
> > > >> > > > >> memory
> > > >> > > > >> mapped
> > > >> > > > >> +       region.
> > > >> > > > >> +- interrupts: The interrupt number to the cpu. The interrupt
> > > >> > > > >> specifier
> > > >> > > > >> format +           depends on the interrupt controller.
> > > >> > > > >> +- clocks: Must contain an entry for each entry in clock-names.
> > > >> > > > >> +- clock-names: Shall be "tsadc" for the converter-clock, and
> > > >> > > > >> "apb_pclk" for +            the peripheral clock.
> > > >> > > > > 
> > > >> > > > > You're using the passive-temp, critical-temp and force-shut-temp
> > > >> > > > > properties in your driver without declaring them here.
> > > >> > > > 
> > > >> > > > frankly,the about are need be declared. but  there are 4 types[0]
> > > >> > > > for
> > > >> > > > trip in thermal framework,
> > > >> > > > there is no force-shut for me. So I want to change it three
> > > >> > > > additional
> > > >> > > > properties in [PATCH V4 4/4],
> > > >> > > > 
> > > >> > > > 
> > > >> > > > [0]
> > > >> > > > {
> > > >> > > > 
> > > >> > > >      THERMAL_TRIP_CRITICAL,
> > > >> > > >      THERMAL_TRIP_HOT,
> > > >> > > >      THERMAL_TRIP_PASSIVE,
> > > >> > > >      THERMAL_TRIP_ACTIVE,
> > > >> > > > 
> > > >> > > > }
> > > >> > > 
> > > >> > > this sounds reasonable to me.
> > > >> > > 
> > > >> > > > > But more importantly, please use the generic trip-points for
> > > >> > > > > this. I
> > > >> > > > > guess it shouldn't be a problem to introduce a "forced-shutdown"
> > > >> > > > > trippoint [0] for the additional trip-point you have - thermal
> > > >> > > > > maintainers, please shout if I'm wrong :-)
> > > >> > > 
> > > >> > > what is the difference between a critical trip point and a
> > > >> > > "forced-shutdown" trip point?
> > > >> > > Thermal core will do a shutdown in case the critical trip point is
> > > >> > > triggered.
> > > >> > 
> > > >> > The forced-shutdown is where the thermal controller is supposed to also
> > > >> > do a>> 
> > > >> Currently, there is no discrimination between hardware configured /
> > > >> triggered thermal shutdown and software detected / triggered thermal
> > > >> shutdown. One way to implement it though is to reuse the critical trip
> > > >> type. Even if you use more than one trip type it is doable, it will
> > > >> depend on the priorities you give to software triggered and hardware
> > > >> triggered.
> > > >> 
> > > >> > shutdown in hardware. As you said the thermal core will also shutdown
> > > >> > at the critical trip point, I guess we could map Caesar's value like
> > > >> > 
> > > >> > trip-point          tsadc
> > > >> > critical            forced-shutdown (the 120 degrees in patch 4)
> > > >> > 
> > > >> > hot                 critical (the 100 degrees)
> > > >> > ...
> > > >> 
> > > >> In the case we are planing to expand the trip type range, adding one
> > > >> specific to hardware configurable shutdown makes sense to me too.
> > > > 
> > > > hmmm, why? you don't want an orderly shutdown? I still do not understand
> > > > why we need a hardware shutdown trip point.
> > > > Say, if we expect the system to be shutdown at 100C, I don't think we
> > > > have a chance to trigger the hardware shutdown trip point.
> > > > Further more, if my understanding is right, thermal core won't do
> > > > anything for the hardware shutdown trip point because the system will be
> > > > shutdown automatically, right? If this is true, why bother introducing
> > > > this to thermal core?
> > > 
> > > Some ICs allow configuring the temperature when the shutdown will
> > > happen. That is, you setup in registers the thermal shutdown
> > > threshold, and one of the output pin of the IC is wired to, say, the
> > > processor reset pin. Some other ICs have the threshold hardwired, and
> > > cannot be configured.
> > > 
> > > Those options are a last chance to avoid processors to burn, in case
> > > software really gets stuck at high temperatures.
> > > 
> > > The only thing that the thermal driver would need to worry is the
> > > configuration step, that is, writing the value to the registers. In
> > > the case the thermal core would have a specific trip type for such
> > > case, the core itself would not do anything, except allowing designing
> > > a thermal zone with hardware shutdown trips. And thus the thermal
> > > driver would do the configuration.
> > > 
> > > 
> > > Currently, the way I see to implement this is to interpret critical
> > > trips as the threshold to be configured at the IC registers. That is,
> > > reusing critical trips as orderly power down and as the hardware
> > > shutdown threshold.
> > 
> > which was what I also meant to express above [but seemingly failed to do 
> > properly :-) ].
> > 
> > Critical is specified as "Hardware not reliable", so I'd think it wouldn't 
> > matter how the hw is shut down (orderly/unorderly) as long as its done.
> 
> Hmmm,
> 
> As what we want is to make thermal driver have a chance to configure the
> hardware shutdown registers, I'm thinking if we can do this without
> representing the hardware shutdown value as a trip point.
> Say,
> 1. parse DT, and get the hardware shutdown temperature value, and store
> it somewhere, e.g. struct __thermal_zone.
> 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> in thermal_zone_of_sensor_register().
> 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> thermal_zone_of_sensor_register().


The only issue I have with the above proposal is that not all platforms
use DT. Some still boot with boardfiles, for instance. Thus, the
parameter to configure hardware thermal shutdown needs to be common on
thermal core, not specific to of-thermal. Do you agree?


> 
> thanks,
> rui
> 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-11 12:18                       ` Eduardo Valentin
@ 2014-09-11 12:32                         ` Arnd Bergmann
  -1 siblings, 0 replies; 65+ messages in thread
From: Arnd Bergmann @ 2014-09-11 12:32 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: Zhang Rui, Heiko Stübner, Caesar Wang, LKML, linux-pm,
	linux-arm-kernel, devicetree, linux-doc, Tao Huang, Eddie Cai,
	Douglas Anderson, dtor, Chris Zhong, addy.ke, Dmitry Torokhov,
	zhaoyifeng

On Thursday 11 September 2014 08:18:43 Eduardo Valentin wrote:
> > As what we want is to make thermal driver have a chance to configure the
> > hardware shutdown registers, I'm thinking if we can do this without
> > representing the hardware shutdown value as a trip point.
> > Say,
> > 1. parse DT, and get the hardware shutdown temperature value, and store
> > it somewhere, e.g. struct __thermal_zone.
> > 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> > in thermal_zone_of_sensor_register().
> > 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> > thermal_zone_of_sensor_register().
> 
> The only issue I have with the above proposal is that not all platforms
> use DT. Some still boot with boardfiles, for instance. Thus, the
> parameter to configure hardware thermal shutdown needs to be common on
> thermal core, not specific to of-thermal. Do you agree?

Do you know of a machine that can't yet be converted to DT and that
needs this driver? In case of rockchips that is certainly not the
case, and we don't care about anybody trying to use board files out
of tree, they can just hack the thermal support as well.

	Arnd

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-11 12:32                         ` Arnd Bergmann
  0 siblings, 0 replies; 65+ messages in thread
From: Arnd Bergmann @ 2014-09-11 12:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 11 September 2014 08:18:43 Eduardo Valentin wrote:
> > As what we want is to make thermal driver have a chance to configure the
> > hardware shutdown registers, I'm thinking if we can do this without
> > representing the hardware shutdown value as a trip point.
> > Say,
> > 1. parse DT, and get the hardware shutdown temperature value, and store
> > it somewhere, e.g. struct __thermal_zone.
> > 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> > in thermal_zone_of_sensor_register().
> > 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> > thermal_zone_of_sensor_register().
> 
> The only issue I have with the above proposal is that not all platforms
> use DT. Some still boot with boardfiles, for instance. Thus, the
> parameter to configure hardware thermal shutdown needs to be common on
> thermal core, not specific to of-thermal. Do you agree?

Do you know of a machine that can't yet be converted to DT and that
needs this driver? In case of rockchips that is certainly not the
case, and we don't care about anybody trying to use board files out
of tree, they can just hack the thermal support as well.

	Arnd

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 3/4] ARM: dts: add main Thermal info to rk3288
  2014-09-10  2:49       ` Caesar Wang
  (?)
@ 2014-09-11 13:58         ` Heiko Stübner
  -1 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-11 13:58 UTC (permalink / raw)
  To: Caesar Wang
  Cc: rui.zhang, edubezval, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov

Hi Caesar,

Am Mittwoch, 10. September 2014, 10:49:05 schrieb Caesar Wang:
> Hi Heiko,
> 
> 在 2014年09月09日 19:37, Heiko Stübner 写道:
> > Am Mittwoch, 3. September 2014, 10:10:38 schrieb Caesar Wang:
> >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> >> ---
> >> 
> >>   arch/arm/boot/dts/rk3288.dtsi | 18 ++++++++++++++++++
> >>   1 file changed, 18 insertions(+)
> >> 
> >> diff --git a/arch/arm/boot/dts/rk3288.dtsi
> >> b/arch/arm/boot/dts/rk3288.dtsi
> >> index 36be7bb..3d672e3 100644
> >> --- a/arch/arm/boot/dts/rk3288.dtsi
> >> +++ b/arch/arm/boot/dts/rk3288.dtsi

[...]

> >> @@ -611,5 +622,12 @@
> >> 
> >>   				rockchip,pins = <5 15 3 &pcfg_pull_none>;
> >>   			
> >>   			};
> >>   		
> >>   		};
> >> 
> >> +
> >> +		tsadc {
> >> +			tsadc_int: tsadc-int {
> >> +				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
> >> +			};
> >> +		};
> > 
> > After looking this up in the schematics I see that this is the
> > overtemperature-protection output pin ... labeled OTP_OUT.
> > So I'd think the pinconfig should reflect this pin-name, especially as
> > tsadc-int suggests, that this would be an interrupt leading into the
> > tsadc, while in fact it is an output to a separate circuit.
> 
> Maybe,I guess  your mean as the follows .
> Please correct it and  Laugh out if I got it wrong.

I'll never laugh ... just try get the best solution / trying to understand 
backgrounds.

> 
> tsadc {
>              otp_out: otp-out {
>                  rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_none>;
>              };
> 
>              tsadc_int: tsadc-int {
>                  rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>;
>              };
>          };
> Then,I deal with the otp_out in thermal driver.
> I believe The "otp_out" will restart board if it's a high active.
> 
> tsadc_int: tsadc-int {
> +				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
> +			};
> 
> But,I think the about will be implemented in thermal driver.

I only meant the pin name (tsadc-int -> otp-out). In the schmatics the pin 
(controlled by the tsadc) is labeled otp_out and leads to the overtemperature 
protection circuit as expected. And as it's controlled by the tsadc, it should 
of course stay as the desired func_1.


Heiko

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 3/4] ARM: dts: add main Thermal info to rk3288
@ 2014-09-11 13:58         ` Heiko Stübner
  0 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-11 13:58 UTC (permalink / raw)
  To: Caesar Wang
  Cc: huangtao, devicetree, addy.ke, dmitry.torokhov, linux-pm,
	linux-doc, linux-kernel, dianders, edubezval, zyw, cf, rui.zhang,
	dtor, linux-arm-kernel

Hi Caesar,

Am Mittwoch, 10. September 2014, 10:49:05 schrieb Caesar Wang:
> Hi Heiko,
> 
> 在 2014年09月09日 19:37, Heiko Stübner 写道:
> > Am Mittwoch, 3. September 2014, 10:10:38 schrieb Caesar Wang:
> >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> >> ---
> >> 
> >>   arch/arm/boot/dts/rk3288.dtsi | 18 ++++++++++++++++++
> >>   1 file changed, 18 insertions(+)
> >> 
> >> diff --git a/arch/arm/boot/dts/rk3288.dtsi
> >> b/arch/arm/boot/dts/rk3288.dtsi
> >> index 36be7bb..3d672e3 100644
> >> --- a/arch/arm/boot/dts/rk3288.dtsi
> >> +++ b/arch/arm/boot/dts/rk3288.dtsi

[...]

> >> @@ -611,5 +622,12 @@
> >> 
> >>   				rockchip,pins = <5 15 3 &pcfg_pull_none>;
> >>   			
> >>   			};
> >>   		
> >>   		};
> >> 
> >> +
> >> +		tsadc {
> >> +			tsadc_int: tsadc-int {
> >> +				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
> >> +			};
> >> +		};
> > 
> > After looking this up in the schematics I see that this is the
> > overtemperature-protection output pin ... labeled OTP_OUT.
> > So I'd think the pinconfig should reflect this pin-name, especially as
> > tsadc-int suggests, that this would be an interrupt leading into the
> > tsadc, while in fact it is an output to a separate circuit.
> 
> Maybe,I guess  your mean as the follows .
> Please correct it and  Laugh out if I got it wrong.

I'll never laugh ... just try get the best solution / trying to understand 
backgrounds.

> 
> tsadc {
>              otp_out: otp-out {
>                  rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_none>;
>              };
> 
>              tsadc_int: tsadc-int {
>                  rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>;
>              };
>          };
> Then,I deal with the otp_out in thermal driver.
> I believe The "otp_out" will restart board if it's a high active.
> 
> tsadc_int: tsadc-int {
> +				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
> +			};
> 
> But,I think the about will be implemented in thermal driver.

I only meant the pin name (tsadc-int -> otp-out). In the schmatics the pin 
(controlled by the tsadc) is labeled otp_out and leads to the overtemperature 
protection circuit as expected. And as it's controlled by the tsadc, it should 
of course stay as the desired func_1.


Heiko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 3/4] ARM: dts: add main Thermal info to rk3288
@ 2014-09-11 13:58         ` Heiko Stübner
  0 siblings, 0 replies; 65+ messages in thread
From: Heiko Stübner @ 2014-09-11 13:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Caesar,

Am Mittwoch, 10. September 2014, 10:49:05 schrieb Caesar Wang:
> Hi Heiko,
> 
> ? 2014?09?09? 19:37, Heiko St?bner ??:
> > Am Mittwoch, 3. September 2014, 10:10:38 schrieb Caesar Wang:
> >> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
> >> ---
> >> 
> >>   arch/arm/boot/dts/rk3288.dtsi | 18 ++++++++++++++++++
> >>   1 file changed, 18 insertions(+)
> >> 
> >> diff --git a/arch/arm/boot/dts/rk3288.dtsi
> >> b/arch/arm/boot/dts/rk3288.dtsi
> >> index 36be7bb..3d672e3 100644
> >> --- a/arch/arm/boot/dts/rk3288.dtsi
> >> +++ b/arch/arm/boot/dts/rk3288.dtsi

[...]

> >> @@ -611,5 +622,12 @@
> >> 
> >>   				rockchip,pins = <5 15 3 &pcfg_pull_none>;
> >>   			
> >>   			};
> >>   		
> >>   		};
> >> 
> >> +
> >> +		tsadc {
> >> +			tsadc_int: tsadc-int {
> >> +				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
> >> +			};
> >> +		};
> > 
> > After looking this up in the schematics I see that this is the
> > overtemperature-protection output pin ... labeled OTP_OUT.
> > So I'd think the pinconfig should reflect this pin-name, especially as
> > tsadc-int suggests, that this would be an interrupt leading into the
> > tsadc, while in fact it is an output to a separate circuit.
> 
> Maybe,I guess  your mean as the follows .
> Please correct it and  Laugh out if I got it wrong.

I'll never laugh ... just try get the best solution / trying to understand 
backgrounds.

> 
> tsadc {
>              otp_out: otp-out {
>                  rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_none>;
>              };
> 
>              tsadc_int: tsadc-int {
>                  rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>;
>              };
>          };
> Then,I deal with the otp_out in thermal driver.
> I believe The "otp_out" will restart board if it's a high active.
> 
> tsadc_int: tsadc-int {
> +				rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_up>;
> +			};
> 
> But,I think the about will be implemented in thermal driver.

I only meant the pin name (tsadc-int -> otp-out). In the schmatics the pin 
(controlled by the tsadc) is labeled otp_out and leads to the overtemperature 
protection circuit as expected. And as it's controlled by the tsadc, it should 
of course stay as the desired func_1.


Heiko

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-11 12:32                         ` Arnd Bergmann
@ 2014-09-11 15:53                           ` Eduardo Valentin
  -1 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-09-11 15:53 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Zhang Rui, Heiko Stübner, Caesar Wang, LKML, linux-pm,
	linux-arm-kernel, devicetree, linux-doc, Tao Huang, Eddie Cai,
	Douglas Anderson, dtor, Chris Zhong, addy.ke, Dmitry Torokhov,
	zhaoyifeng

Arnd,

On Thu, Sep 11, 2014 at 02:32:08PM +0200, Arnd Bergmann wrote:
> On Thursday 11 September 2014 08:18:43 Eduardo Valentin wrote:
> > > As what we want is to make thermal driver have a chance to configure the
> > > hardware shutdown registers, I'm thinking if we can do this without
> > > representing the hardware shutdown value as a trip point.
> > > Say,
> > > 1. parse DT, and get the hardware shutdown temperature value, and store
> > > it somewhere, e.g. struct __thermal_zone.
> > > 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> > > in thermal_zone_of_sensor_register().
> > > 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> > > thermal_zone_of_sensor_register().
> > 
> > The only issue I have with the above proposal is that not all platforms
> > use DT. Some still boot with boardfiles, for instance. Thus, the
> > parameter to configure hardware thermal shutdown needs to be common on
> > thermal core, not specific to of-thermal. Do you agree?
> 
> Do you know of a machine that can't yet be converted to DT and that
> needs this driver? In case of rockchips that is certainly not the
> case, and we don't care about anybody trying to use board files out
> of tree, they can just hack the thermal support as well.

I see. Again, the only concern I have is to produce thermal framework APIs
that would be only in the of-thermal. My point is not specific to this
patch, or this platform, but with a detail in the above proposal. 

While I agree to have a trip specific to configurable hardware triggered
thermal shutdown, I just don't see why it needs to be a feature
implemented only via of-thermal. It has to be properly defined in
thermal core.

The proposal of of-thermal is not to become a separate/competing thermal
framework.

> 
> 	Arnd

Cheers,

Eduardo

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-11 15:53                           ` Eduardo Valentin
  0 siblings, 0 replies; 65+ messages in thread
From: Eduardo Valentin @ 2014-09-11 15:53 UTC (permalink / raw)
  To: linux-arm-kernel

Arnd,

On Thu, Sep 11, 2014 at 02:32:08PM +0200, Arnd Bergmann wrote:
> On Thursday 11 September 2014 08:18:43 Eduardo Valentin wrote:
> > > As what we want is to make thermal driver have a chance to configure the
> > > hardware shutdown registers, I'm thinking if we can do this without
> > > representing the hardware shutdown value as a trip point.
> > > Say,
> > > 1. parse DT, and get the hardware shutdown temperature value, and store
> > > it somewhere, e.g. struct __thermal_zone.
> > > 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> > > in thermal_zone_of_sensor_register().
> > > 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> > > thermal_zone_of_sensor_register().
> > 
> > The only issue I have with the above proposal is that not all platforms
> > use DT. Some still boot with boardfiles, for instance. Thus, the
> > parameter to configure hardware thermal shutdown needs to be common on
> > thermal core, not specific to of-thermal. Do you agree?
> 
> Do you know of a machine that can't yet be converted to DT and that
> needs this driver? In case of rockchips that is certainly not the
> case, and we don't care about anybody trying to use board files out
> of tree, they can just hack the thermal support as well.

I see. Again, the only concern I have is to produce thermal framework APIs
that would be only in the of-thermal. My point is not specific to this
patch, or this platform, but with a detail in the above proposal. 

While I agree to have a trip specific to configurable hardware triggered
thermal shutdown, I just don't see why it needs to be a feature
implemented only via of-thermal. It has to be properly defined in
thermal core.

The proposal of of-thermal is not to become a separate/competing thermal
framework.

> 
> 	Arnd

Cheers,

Eduardo

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-11 15:53                           ` Eduardo Valentin
@ 2014-09-16  7:23                             ` Zhang Rui
  -1 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-16  7:23 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: Arnd Bergmann, Heiko Stübner, Caesar Wang, LKML, linux-pm,
	linux-arm-kernel, devicetree, linux-doc, Tao Huang, Eddie Cai,
	Douglas Anderson, dtor, Chris Zhong, addy.ke, Dmitry Torokhov,
	zhaoyifeng

On Thu, 2014-09-11 at 11:53 -0400, Eduardo Valentin wrote:
> Arnd,
> 
> On Thu, Sep 11, 2014 at 02:32:08PM +0200, Arnd Bergmann wrote:
> > On Thursday 11 September 2014 08:18:43 Eduardo Valentin wrote:
> > > > As what we want is to make thermal driver have a chance to configure the
> > > > hardware shutdown registers, I'm thinking if we can do this without
> > > > representing the hardware shutdown value as a trip point.
> > > > Say,
> > > > 1. parse DT, and get the hardware shutdown temperature value, and store
> > > > it somewhere, e.g. struct __thermal_zone.
> > > > 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> > > > in thermal_zone_of_sensor_register().
> > > > 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> > > > thermal_zone_of_sensor_register().
> > > 
> > > The only issue I have with the above proposal is that not all platforms
> > > use DT. Some still boot with boardfiles, for instance. Thus, the
> > > parameter to configure hardware thermal shutdown needs to be common on
> > > thermal core, not specific to of-thermal. Do you agree?
> > 
> > Do you know of a machine that can't yet be converted to DT and that
> > needs this driver? In case of rockchips that is certainly not the
> > case, and we don't care about anybody trying to use board files out
> > of tree, they can just hack the thermal support as well.
> 
> I see. Again, the only concern I have is to produce thermal framework APIs
> that would be only in the of-thermal. My point is not specific to this
> patch, or this platform, but with a detail in the above proposal. 
> 
> While I agree to have a trip specific to configurable hardware triggered
> thermal shutdown, I just don't see why it needs to be a feature
> implemented only via of-thermal. It has to be properly defined in
> thermal core.
> 
> The proposal of of-thermal is not to become a separate/competing thermal
> framework.
> 
Agreed.
And I think we can have such feature in thermal core.
But again I don't think we should represent it as an trip point. 

thanks,
rui
> > 
> > 	Arnd
> 
> Cheers,
> 
> Eduardo



^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-16  7:23                             ` Zhang Rui
  0 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-16  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 2014-09-11 at 11:53 -0400, Eduardo Valentin wrote:
> Arnd,
> 
> On Thu, Sep 11, 2014 at 02:32:08PM +0200, Arnd Bergmann wrote:
> > On Thursday 11 September 2014 08:18:43 Eduardo Valentin wrote:
> > > > As what we want is to make thermal driver have a chance to configure the
> > > > hardware shutdown registers, I'm thinking if we can do this without
> > > > representing the hardware shutdown value as a trip point.
> > > > Say,
> > > > 1. parse DT, and get the hardware shutdown temperature value, and store
> > > > it somewhere, e.g. struct __thermal_zone.
> > > > 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> > > > in thermal_zone_of_sensor_register().
> > > > 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> > > > thermal_zone_of_sensor_register().
> > > 
> > > The only issue I have with the above proposal is that not all platforms
> > > use DT. Some still boot with boardfiles, for instance. Thus, the
> > > parameter to configure hardware thermal shutdown needs to be common on
> > > thermal core, not specific to of-thermal. Do you agree?
> > 
> > Do you know of a machine that can't yet be converted to DT and that
> > needs this driver? In case of rockchips that is certainly not the
> > case, and we don't care about anybody trying to use board files out
> > of tree, they can just hack the thermal support as well.
> 
> I see. Again, the only concern I have is to produce thermal framework APIs
> that would be only in the of-thermal. My point is not specific to this
> patch, or this platform, but with a detail in the above proposal. 
> 
> While I agree to have a trip specific to configurable hardware triggered
> thermal shutdown, I just don't see why it needs to be a feature
> implemented only via of-thermal. It has to be properly defined in
> thermal core.
> 
> The proposal of of-thermal is not to become a separate/competing thermal
> framework.
> 
Agreed.
And I think we can have such feature in thermal core.
But again I don't think we should represent it as an trip point. 

thanks,
rui
> > 
> > 	Arnd
> 
> Cheers,
> 
> Eduardo

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 2/4] dt-bindings: document Rockchip thermal
  2014-09-11 15:53                           ` Eduardo Valentin
@ 2014-09-16  7:45                             ` Zhang Rui
  -1 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-16  7:45 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: Arnd Bergmann, Heiko Stübner, Caesar Wang, LKML, linux-pm,
	linux-arm-kernel, devicetree, linux-doc, Tao Huang, Eddie Cai,
	Douglas Anderson, dtor, Chris Zhong, addy.ke, Dmitry Torokhov,
	zhaoyifeng


On Thu, 2014-09-11 at 11:53 -0400, Eduardo Valentin wrote:
> Arnd,
> 
> On Thu, Sep 11, 2014 at 02:32:08PM +0200, Arnd Bergmann wrote:
> > On Thursday 11 September 2014 08:18:43 Eduardo Valentin wrote:
> > > > As what we want is to make thermal driver have a chance to configure the
> > > > hardware shutdown registers, I'm thinking if we can do this without
> > > > representing the hardware shutdown value as a trip point.
> > > > Say,
> > > > 1. parse DT, and get the hardware shutdown temperature value, and store
> > > > it somewhere, e.g. struct __thermal_zone.
> > > > 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> > > > in thermal_zone_of_sensor_register().
> > > > 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> > > > thermal_zone_of_sensor_register().
> > > 
> > > The only issue I have with the above proposal is that not all platforms
> > > use DT. Some still boot with boardfiles, for instance. Thus, the
> > > parameter to configure hardware thermal shutdown needs to be common on
> > > thermal core, not specific to of-thermal. Do you agree?
> > 
> > Do you know of a machine that can't yet be converted to DT and that
> > needs this driver? In case of rockchips that is certainly not the
> > case, and we don't care about anybody trying to use board files out
> > of tree, they can just hack the thermal support as well.
> 
> I see. Again, the only concern I have is to produce thermal framework APIs
> that would be only in the of-thermal. My point is not specific to this
> patch, or this platform, but with a detail in the above proposal. 
> 
> While I agree to have a trip specific to configurable hardware triggered
> thermal shutdown, I just don't see why it needs to be a feature
> implemented only via of-thermal. It has to be properly defined in
> thermal core.
> 
> The proposal of of-thermal is not to become a separate/competing thermal
> framework.
> 
Agreed.
And I think we can have such feature in thermal core.
But again I don't think we should represent it as an trip point.
Instead, we can have a separate parameter for

thanks,
rui
> > 
> > 	Arnd
> 
> Cheers,
> 
> Eduardo




^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 2/4] dt-bindings: document Rockchip thermal
@ 2014-09-16  7:45                             ` Zhang Rui
  0 siblings, 0 replies; 65+ messages in thread
From: Zhang Rui @ 2014-09-16  7:45 UTC (permalink / raw)
  To: linux-arm-kernel


On Thu, 2014-09-11 at 11:53 -0400, Eduardo Valentin wrote:
> Arnd,
> 
> On Thu, Sep 11, 2014 at 02:32:08PM +0200, Arnd Bergmann wrote:
> > On Thursday 11 September 2014 08:18:43 Eduardo Valentin wrote:
> > > > As what we want is to make thermal driver have a chance to configure the
> > > > hardware shutdown registers, I'm thinking if we can do this without
> > > > representing the hardware shutdown value as a trip point.
> > > > Say,
> > > > 1. parse DT, and get the hardware shutdown temperature value, and store
> > > > it somewhere, e.g. struct __thermal_zone.
> > > > 2. introduce a new parameter, int (*set_hardware_trip)(void *, long *),
> > > > in thermal_zone_of_sensor_register().
> > > > 3. invoke set_hard_trip(tz, hardware_shutdown_temperature_value) in
> > > > thermal_zone_of_sensor_register().
> > > 
> > > The only issue I have with the above proposal is that not all platforms
> > > use DT. Some still boot with boardfiles, for instance. Thus, the
> > > parameter to configure hardware thermal shutdown needs to be common on
> > > thermal core, not specific to of-thermal. Do you agree?
> > 
> > Do you know of a machine that can't yet be converted to DT and that
> > needs this driver? In case of rockchips that is certainly not the
> > case, and we don't care about anybody trying to use board files out
> > of tree, they can just hack the thermal support as well.
> 
> I see. Again, the only concern I have is to produce thermal framework APIs
> that would be only in the of-thermal. My point is not specific to this
> patch, or this platform, but with a detail in the above proposal. 
> 
> While I agree to have a trip specific to configurable hardware triggered
> thermal shutdown, I just don't see why it needs to be a feature
> implemented only via of-thermal. It has to be properly defined in
> thermal core.
> 
> The proposal of of-thermal is not to become a separate/competing thermal
> framework.
> 
Agreed.
And I think we can have such feature in thermal core.
But again I don't think we should represent it as an trip point.
Instead, we can have a separate parameter for

thanks,
rui
> > 
> > 	Arnd
> 
> Cheers,
> 
> Eduardo

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH v4 1/4] thermal: rockchip: add driver for thermal
  2014-09-10 12:46         ` Eduardo Valentin
@ 2014-09-17  7:29           ` Caesar Wang
  -1 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-17  7:29 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: heiko, rui.zhang, linux-kernel, linux-pm, linux-arm-kernel,
	devicetree, linux-doc, huangtao, cf, dianders, dtor, zyw,
	addy.ke, dmitry.torokhov, zhaoyifeng

Eduardo,

在 2014/9/10 20:46, Eduardo Valentin 写道:
> Hello Caesar,
>
> On Wed, Sep 10, 2014 at 12:39:07PM +0800, Caesar Wang wrote:
>> Dear Eduardo,
>>
>> I'm  sorry for it.
>> I just received this message.Maybe my mailbox has a problem.
>
> No problems. You can take your time.
>
>> Thank you for your comments.
>>
>> 在 2014年08月31日 04:09, Eduardo Valentin 写道:
>>> Hello Ceasar,
>>>
>>> On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
>>>> Thermal is TS-ADC Controller module supports
>>>> user-defined mode and automatic mode.
>>>>
>>>> User-defined mode refers,TSADC all the control signals entirely by
>>>> software writing to register for direct control.
>>>>
>>>> Automaic mode refers to the module automatically poll TSADC output,
>>>> and the results were checked.If you find that the temperature High
>>>> in a period of time,an interrupt is generated to the processor
>>>> down-measures taken;if the temperature over a period of time High,
>>>> the resulting TSHUT gave CRU module,let it reset the entire chip,
>>>> or via GPIO give PMIC.
>>>>
>>>> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> I forgot to ask, is zhaoyifeng the correct name or is it a nickname?
>
>>>> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>>>> ---
>>>>    drivers/thermal/Kconfig            |   9 +
>>>>    drivers/thermal/Makefile           |   1 +
>>>>    drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
>>>>    3 files changed, 679 insertions(+)
>>>>    create mode 100644 drivers/thermal/rockchip_thermal.c
>>>>
>>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>>> index f9a1386..a00aa1e 100644
>>>> --- a/drivers/thermal/Kconfig
>>>> +++ b/drivers/thermal/Kconfig
>>>> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
>>>>    	  Enable this to plug the SPEAr thermal sensor driver into the Linux
>>>>    	  thermal framework.
>>>>    
>>>> +config ROCKCHIP_THERMAL
>>>> +	tristate "Rockchip thermal driver"
>>>> +	depends on ARCH_ROCKCHIP
>>>> +	help
>>>> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
>>>> +	  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 RCAR_THERMAL
>>>>    	tristate "Renesas R-Car thermal driver"
>>>>    	depends on ARCH_SHMOBILE || COMPILE_TEST
>>>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>>>> index de0636a..b48b817 100644
>>>> --- a/drivers/thermal/Makefile
>>>> +++ b/drivers/thermal/Makefile
>>>> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
>>>>    
>>>>    # platform thermal drivers
>>>>    obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
>>>> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
>>>>    obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
>>>>    obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
>>>>    obj-y				+= samsung/
>>>> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
>>>> new file mode 100644
>>>> index 0000000..011f387
>>>> --- /dev/null
>>>> +++ b/drivers/thermal/rockchip_thermal.c
>>>> @@ -0,0 +1,669 @@
>>>> +/*
>>>> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
>>>> + *
>>>> + * 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/clk.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/of_irq.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/regulator/consumer.h>
>>>> +#include <linux/cpu_cooling.h>
>>>> +#include "thermal_core.h"
>>> Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
>>> sufficient?
>>>
>> yes, I will use linux/thermal.h.
>>>> +
>>>> +enum rockchip_thermal_trip {
>>>> +	ROCKCHIP_TRIP_PASSIVE,
>>>> +	ROCKCHIP_TRIP_CRITICAL,
>>>> +	ROCKCHIP_TRIP_NUM,
>>>> +};
>>>> +
>>> Why do you need your own trip types?
>>>
>>>> +struct rockchip_thermal_data {
>>>> +	const struct rockchip_tsadc_platform_data *pdata;
>>>> +	struct thermal_zone_device *tz;
>>>> +	struct thermal_cooling_device *cdev;
>>>> +	enum thermal_device_mode mode;
>>>> +	void __iomem *regs;
>>>> +
>>>> +	signed long temp_passive;
>>>> +	signed long temp_critical;
>>>> +	signed long temp_force_shut;
>>>> +	signed long alarm_temp;
>>>> +	signed long last_temp;
>>>> +	bool irq_enabled;
>>>> +	int irq;
>>>> +	struct clk *clk;
>>>> +	struct clk *pclk;
>>>> +};
>>>> +
>>>> +struct rockchip_tsadc_platform_data {
>>>> +	u8 irq_en;
>>>> +	signed long temp_passive;
>>>> +	signed long temp_critical;
>>>> +	signed long temp_force_shut;
>>>> +	int passive_delay;
>>>> +	int polling_delay;
>>>> +
>>>> +	int (*irq_handle)(void __iomem *reg);
>>>> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
>>>> +	int (*control)(void __iomem *reg, bool on);
>>>> +	u32 (*code_to_temp)(int temp);
>>>> +	u32 (*temp_to_code)(int temp);
>>>> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
>>>> +};
>>>> +
>>>> +/*TSADC V2 Sensor info define:*/
>>>> +#define TSADCV2_AUTO_CON			0x04
>>>> +#define TSADCV2_INT_EN				0x08
>>>> +#define TSADCV2_INT_PD				0x0c
>>>> +#define TSADCV2_DATA1				0x24
>>>> +#define TSADCV2_COMP1_INT			0x34
>>>> +#define TSADCV2_COMP1_SHUT			0x44
>>>> +#define TSADCV2_AUTO_PERIOD			0x68
>>>> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
>>>> +
>>>> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
>>>> +#define TSADCV2_AUTO_EN				(1 << 0)
>>>> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
>>>> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
>>>> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
>>>> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
>>>> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
>>>> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
>>>> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
>>>> +
>>> The above bits can be defined with BIT() macro, right?
>> Yes. The Bit() will be more resonable..
>>>    Something like:
>>> +#define TSADCV2_INT_SRC1_STATUS			BIT(1)
>>>
>>>
>>>> +#define TSADCV2_DATA_MASK			0xfff
>>>> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
>>>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
>>>> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
>>>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
>>>> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
>>>> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
>>>> +
>>>> +struct tsadc_table {
>>>> +	int code;
>>>> +	int temp;
>>>> +};
>>>> +
>>>> +static const struct tsadc_table v2_code_table[] = {
>>>> +	{TSADCV2_DATA_MASK, -40},
>>>> +	{3800, -40},
>>>> +	{3792, -35},
>>>> +	{3783, -30},
>>>> +	{3774, -25},
>>>> +	{3765, -20},
>>>> +	{3756, -15},
>>>> +	{3747, -10},
>>>> +	{3737, -5},
>>>> +	{3728, 0},
>>>> +	{3718, 5},
>>>> +	{3708, 10},
>>>> +	{3698, 15},
>>>> +	{3688, 20},
>>>> +	{3678, 25},
>>>> +	{3667, 30},
>>>> +	{3656, 35},
>>>> +	{3645, 40},
>>>> +	{3634, 45},
>>>> +	{3623, 50},
>>>> +	{3611, 55},
>>>> +	{3600, 60},
>>>> +	{3588, 65},
>>>> +	{3575, 70},
>>>> +	{3563, 75},
>>>> +	{3550, 80},
>>>> +	{3537, 85},
>>>> +	{3524, 90},
>>>> +	{3510, 95},
>>>> +	{3496, 100},
>>>> +	{3482, 105},
>>>> +	{3467, 110},
>>>> +	{3452, 115},
>>>> +	{3437, 120},
>>>> +	{3421, 125},
>>>> +	{0, 125},
>>>> +};
>>>> +
>>>> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
>>>> +{
>>>> +	u32 val;
>>>> +
>>>> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
>>>> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
>>> Why do you need to clear bit 8? Why hardcoded?
>> The bit 8 set 0 to clear the interrupt.
>>
> Would it make sense to create a macro for this?
>
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static u32 rk_tsadcv2_temp_to_code(int temp)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>>>> +		if (temp <= v2_code_table[i].temp && temp >
>>>> +		    v2_code_table[i - 1].temp)
>>>> +			return v2_code_table[i].code;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static u32 rk_tsadcv2_code_to_temp(int code)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>>>> +		if (code <= v2_code_table[i].code && code >
>>>> +		    v2_code_table[i + 1].code){
>>>> +			return v2_code_table[i].temp;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> I know the table is not something too big, but considering it is ordered
>>> by either ADC value code or by temp, at least one of the above searching function
>>> may be more efficient, right?

In general,I should use dichotomy,Say, as the follows:

static u32 rk_tsadcv2_temp_to_code(int temp)
{
   int low = 0, high, mid;
   high =  ARRAY_SIZE(v2_code_table) - 1;
   ......

     while(high >= low) {
             mid = (high + low)/2;
             if (v2_code_table[mid].temp == temp)
                 return v2_code_table[mid].code;
             if (v2_code_table[mid].temp > temp)
                 high = mid - 1;
             if (v2_code_table[mid].temp < temp)
                 low = mid + 1;
     }
}

but, I better like to use the follows than the about.

static u32 rk_tsadcv2_temp_to_code(int temp)
{
     int i;

     for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
         if (temp <= v2_code_table[i].temp)
             return v2_code_table[i].code;
     }

     return 0;
}

Do you agree?

I sent Patch v5,you can review again,if you are available.
>> Yes, use the point will be more efficient.
>>>> +
>>>> +static int rk_tsadcv2_initialize(void __iomem *regs,
>>>> +				 signed long temp_force_shut)
>>>> +{
>>>> +	int shutdown_value;
>>>> +
>>>> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
>>>> +	/* Enable measurements at ~ 10 Hz */
>>> Does it leave the sampling clock at 10Hz?
>> yes.
> ok
>
>
>>> Is this clock exposed via
>>> clock framework?
>> The clock is divided by data->clk.
> ok
>
>>>> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
>>>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
>>>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
>>>> +		       TSADCV2_AUTO_PERIOD_HT);
>>>> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
>>>> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
>>>> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
>>>> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
>>>> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
>>>> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
>>>> +		       TSADCV2_INT_EN);
>>>> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
>>>> +		       TSADCV2_AUTO_CON);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
>>>> +{
>>>> +	u32 val;
>>>> +
>>>> +	if (on) {
>>>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>>>> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
>>>> +	} else {
>>>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>>>> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
>>>> +			       regs + TSADCV2_AUTO_CON);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
>>>> +{
>>>> +	int alarm_value;
>>>> +
>>>> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
>>>> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
>>>> +}
>>>> +
>>>> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
>>>> +	.irq_en = 1,
>>>> +	.temp_passive = 85000,
>>>> +	.temp_critical = 100000,
>>>> +	.temp_force_shut = 120000,
>>>> +	.passive_delay = 2000,
>>>> +	.polling_delay = 1000,
>>>> +	.irq_handle = rk_tsadcv2_irq_handle,
>>>> +	.initialize = rk_tsadcv2_initialize,
>>>> +	.control = rk_tsadcv2_control,
>>>> +	.code_to_temp = rk_tsadcv2_code_to_temp,
>>>> +	.temp_to_code = rk_tsadcv2_temp_to_code,
>>>> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
>>>> +};
>>> shall the above struct be also static?
>> OK.
>>>> +
>>>> +static const struct of_device_id of_rockchip_thermal_match[] = {
>>>> +	{
>>>> +		.compatible = "rockchip,rk3288-tsadc",
>>>> +		.data = (void *)&rk3288_tsadc_data,
>>>> +	},
>>>> +	{ /* end */ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
>>>> +
>>>> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
>>>> +				    signed long alarm_temp)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	data->alarm_temp = alarm_temp;
>>>> +	if (p_tsadc_data->set_alarm_temp)
>>>> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
>>>> +}
>>>> +
>>>> +static int rockchip_get_temp(struct thermal_zone_device *tz,
>>>> +			     unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +	u32 val;
>>>> +
>>>> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
>>>> +	*temp = p_tsadc_data->code_to_temp(val);
>>>> +
>>>> +	/* Update alarm value to next higher trip point */
>>>> +	if (data->alarm_temp == data->temp_passive && *temp >=
>>>> +	    data->temp_passive)
>>>> +		rockchip_set_alarm_temp(data, data->temp_critical);
>>>> +
>>>> +	if (data->alarm_temp == data->temp_critical && *temp <
>>>> +	    data->temp_passive) {
>>>> +		rockchip_set_alarm_temp(data, data->temp_passive);
>>>> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
>>>> +			data->alarm_temp / 1000);
>>>> +	}
>>>> +
>>>> +	if (*temp != data->last_temp) {
>>>> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
>>>> +		data->last_temp = *temp;
>>>> +	}
>>>> +
>>>> +	/* Reenable alarm IRQ if temperature below alarm temperature */
>>>> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
>>>> +		data->irq_enabled = true;
>>>> +		enable_irq(data->irq);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (p_tsadc_data->initialize)
>>>> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
>>>> +	rockchip_set_alarm_temp(data, data->temp_passive);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
>>>> +				     bool on)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (p_tsadc_data->control)
>>>> +		p_tsadc_data->control(data->regs, on);
>>>> +
>>>> +	if (on) {
>>>> +		data->irq_enabled = true;
>>>> +		data->mode = THERMAL_DEVICE_ENABLED;
>>>> +	} else {
>>>> +		data->irq_enabled = false;
>>>> +		data->mode = THERMAL_DEVICE_DISABLED;
>>>> +	}
>>>> +}
>>>> +
>>>> +static int rockchip_get_mode(struct thermal_zone_device *tz,
>>>> +			     enum thermal_device_mode *mode)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*mode = data->mode;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_set_mode(struct thermal_zone_device *tz,
>>>> +			     enum thermal_device_mode mode)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (mode == THERMAL_DEVICE_ENABLED) {
>>>> +		tz->polling_delay = p_tsadc_data->polling_delay;
>>>> +		tz->passive_delay = p_tsadc_data->passive_delay;
>>>> +		if (!data->irq_enabled) {
>>>> +			data->irq_enabled = true;
>>>> +			enable_irq(data->irq);
>>>> +		}
>>>> +	} else {
>>>> +		tz->polling_delay = 0;
>>>> +		tz->passive_delay = 0;
>>>> +		if (data->irq_enabled) {
>>>> +			disable_irq(data->irq);
>>>> +			data->irq_enabled = false;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	data->mode = mode;
>>>> +	thermal_zone_device_update(tz);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
>>>> +				  enum thermal_trip_type *type)
>>>> +{
>>>> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
>>>> +		 THERMAL_TRIP_CRITICAL;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
>>>> +				  unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*temp = data->temp_critical;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
>>>> +				  unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
>>>> +		 data->temp_critical;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
>>>> +				  unsigned long temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
>>>> +		return -EPERM;
>>>> +
>>>> +	data->temp_passive = temp;
>>>> +	rockchip_set_alarm_temp(data, temp);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_bind(struct thermal_zone_device *tz,
>>>> +			 struct thermal_cooling_device *cdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
>>>> +					       THERMAL_NO_LIMIT,
>>>> +					       THERMAL_NO_LIMIT);
>>>> +	if (ret) {
>>>> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>>>> +			tz->type, cdev->type, ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_unbind(struct thermal_zone_device *tz,
>>>> +			   struct thermal_cooling_device *cdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = thermal_zone_unbind_cooling_device(tz,
>>>> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
>>>> +	if (ret) {
>>>> +		dev_err(&tz->device,
>>>> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
>>>> +			cdev->type, ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> The method of binding and unbinding used above requires you to check if
>>> you are binding to the right cdev. If in your system you register more
>>> than one cdev, say someone loads the power supply core, which in turns
>>> register a cooling device for charging, your thermal zone will bind it
>>> to TRIP_PASSIVE. It will happen to any cooling device that eventually
>>> gets registered to the thermal framework. Is that the desired outcome?
>> Yes,I will use the generic trip points in the dts and fix it in the
>> thermal driver.
> great
>
>>> If not, you may want to compare the paramenter cdev to your data->cdev.
>>>
>>>> +
>>>> +static struct thermal_zone_device_ops rockchip_tz_ops = {
>>>> +	.bind = rockchip_bind,
>>>> +	.unbind = rockchip_unbind,
>>>> +	.get_temp = rockchip_get_temp,
>>>> +	.get_mode = rockchip_get_mode,
>>>> +	.set_mode = rockchip_set_mode,
>>>> +	.get_trip_type = rockchip_get_trip_type,
>>>> +	.get_trip_temp = rockchip_get_trip_temp,
>>>> +	.get_crit_temp = rockchip_get_crit_temp,
>>>> +	.set_trip_temp = rockchip_set_trip_temp,
>>>> +};
>>>> +
>>>> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = data;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
>>>> +		data->alarm_temp / 1000);
>>>> +
>>>> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
>>>> +		p_tsadc_data->irq_handle(data->regs);
>>>> +
>>>> +	thermal_zone_device_update(data->tz);
>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_probe(struct platform_device *pdev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
>>>> +	struct cpumask clip_cpus;
>>>> +	struct resource *res;
>>>> +	const struct of_device_id *match;
>>>> +	int ret, temp;
>>>> +
>>>> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
>>>> +			    GFP_KERNEL);
>>>> +	if (!data)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
>>>> +	if (IS_ERR(data->regs)) {
>>>> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
>>>> +			data->regs);
>>>> +		return PTR_ERR(data->regs);
>>>> +	}
>>>> +
>>>> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
>>>> +	if (!match)
>>>> +		return -ENXIO;
>>>> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
>>>> +	if (!data->pdata)
>>>> +		return -EINVAL;
>>>> +	p_tsadc_data = data->pdata;
>>>> +
>>>> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
>>>> +	if (IS_ERR(data->clk)) {
>>>> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
>>>> +		return PTR_ERR(data->clk);
>>>> +	}
>>>> +
>>>> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
>>>> +	if (IS_ERR(data->pclk)) {
>>>> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
>>>> +		return PTR_ERR(data->pclk);
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	* Use a default of 10KHz for the converter clock.
>>>> +	* This may become user-configurable in the future.
>>>> +	*/
>>>> +	ret = clk_set_rate(data->clk, 10000);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(data->clk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
>>>> +		goto err_clk;
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(data->pclk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to enable pclk\n");
>>>> +		goto err_pclk;
>>>> +	}
>>>> +
>>>> +	platform_set_drvdata(pdev, data);
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default passive temp property in the DT.\n");
>>>> +		data->temp_passive = p_tsadc_data->temp_passive;
>>>> +	} else {
>>>> +		data->temp_passive = temp;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default critical temp property in the DT.\n");
>>>> +		data->temp_critical = p_tsadc_data->temp_critical;
>>>> +	} else {
>>>> +		data->temp_critical = temp;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default force shut down temp property in the DT.\n");
>>>> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
>>>> +	} else {
>>>> +		data->temp_force_shut = temp;
>>>> +	}
>>>> +
>>>> +	cpumask_set_cpu(0, &clip_cpus);
>>>> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
>>>> +	if (IS_ERR(data->cdev)) {
>>>> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
>>>> +		goto disable_clk;
>>>> +	}
>>>> +
>>>> +	data->tz = thermal_zone_device_register("rockchip_thermal",
>>>> +						ROCKCHIP_TRIP_NUM,
>>>> +						0, data,
>>>> +						&rockchip_tz_ops, NULL,
>>>> +						p_tsadc_data->passive_delay,
>>>> +						p_tsadc_data->polling_delay);
>>>> +
>>>> +	if (IS_ERR(data->tz)) {
>>>> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
>>>> +		goto fail_cpufreq_register;
>>>> +	}
>>>> +
>>>> +	if (p_tsadc_data->irq_en) {
>>>> +		data->irq = platform_get_irq(pdev, 0);
>>>> +		if (data->irq < 0) {
>>>> +			dev_err(&pdev->dev, "no irq resource?\n");
>>>> +			goto fail_irq;
>>>> +		}
>>>> +
>>>> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
>>>> +				rockchip_thermal_alarm_irq_thread,
>>>> +				IRQF_ONESHOT, "rockchip_thermal", data);
>>>> +		if (ret < 0) {
>>>> +			dev_err(&pdev->dev,
>>>> +				"failed to request tsadc irq: %d\n", ret);
>>>> +			goto fail_thermal_unregister;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	rockchip_thermal_initialize(data);
>>>> +	rockchip_thermal_control(data, true);
>>>> +
>>>> +	return 0;
>>>> +
>>>> +fail_thermal_unregister:
>>>> +	thermal_zone_device_unregister(data->tz);
>>>> +fail_irq:
>>>> +fail_cpufreq_register:
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +disable_clk:
>>>> +err_pclk:
>>>> +	clk_disable_unprepare(data->pclk);
>>>> +err_clk:
>>>> +	clk_disable_unprepare(data->clk);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_control(data, false);
>>>> +
>>>> +	thermal_zone_device_unregister(data->tz);
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +
>>> The above call is duplicated.
>> OK.
>>>> +	clk_disable_unprepare(data->clk);
>>>> +	clk_disable_unprepare(data->pclk);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int rockchip_thermal_suspend(struct device *dev)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_control(data, false);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_resume(struct device *dev)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_initialize(data);
>>>> +	rockchip_thermal_control(data, true);
>>>> +
>>>> +	return 0;
>>>> +}
>>> Would you need to manage your clocks too in the suspend resume path
>>> (data->clk and data->pclk)?
>> yes.
>> Usually,it's need disable to save power.
> Yes, that's my point. Please consider handling clocks to improve power
> savings.
>
>>>> +#endif
>>>> +
>>>> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
>>>> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
>>>> +
>>>> +static struct platform_driver rockchip_thermal_driver = {
>>>> +	.driver = {
>>>> +		   .name = "rockchip-thermal",
>>>> +		   .owner = THIS_MODULE,
>>>> +		   .pm = &rockchip_thermal_pm_ops,
>>>> +		   .of_match_table = of_rockchip_thermal_match,
>>>> +		   },
>>>> +	.probe = rockchip_thermal_probe,
>>>> +	.remove = rockchip_thermal_remove,
>>>> +};
>>>> +
>>>> +module_platform_driver(rockchip_thermal_driver);
>>>> +
>>>> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
>>>> +MODULE_AUTHOR("Rockchip, Inc.");
>>>> +MODULE_LICENSE("GPL");
>>> Your file header states GPL version two. Thus I suppose you meant:
>>> +MODULE_LICENSE("GPL v2");
>>>
>>> right?
>>>
>>> Check include/linux/module.h for further clarifications.
>> But I think the  "GPL"  is support for thr GNU Public License v2 or later.
> Exactly, if you intend to support v3, then it is fine. But your code
> header states only V2.
>
>> I will fix GPL v2 if I get it wrong.
> If your license is GPLv2 only as mentioned in your header, please use 'GPL
> v2' tag.
>
> Cheers,
>
>>>> +MODULE_ALIAS("platform:rockchip-thermal");
>>>> -- 
>>>> 1.9.1
>>>>
>>>>
>>> BR,
>>>
>>> Eduardo Valentin
>>>
>>>
>>>
>> -- 
>> Best regards,
>> Caesar
>>
>>
>
>

-- 
Best regards,
Caesar



^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH v4 1/4] thermal: rockchip: add driver for thermal
@ 2014-09-17  7:29           ` Caesar Wang
  0 siblings, 0 replies; 65+ messages in thread
From: Caesar Wang @ 2014-09-17  7:29 UTC (permalink / raw)
  To: linux-arm-kernel

Eduardo,

? 2014/9/10 20:46, Eduardo Valentin ??:
> Hello Caesar,
>
> On Wed, Sep 10, 2014 at 12:39:07PM +0800, Caesar Wang wrote:
>> Dear Eduardo,
>>
>> I'm  sorry for it.
>> I just received this message.Maybe my mailbox has a problem.
>
> No problems. You can take your time.
>
>> Thank you for your comments.
>>
>> ? 2014?08?31? 04:09, Eduardo Valentin ??:
>>> Hello Ceasar,
>>>
>>> On Wed, Sep 03, 2014 at 10:10:36AM +0800, Caesar Wang wrote:
>>>> Thermal is TS-ADC Controller module supports
>>>> user-defined mode and automatic mode.
>>>>
>>>> User-defined mode refers,TSADC all the control signals entirely by
>>>> software writing to register for direct control.
>>>>
>>>> Automaic mode refers to the module automatically poll TSADC output,
>>>> and the results were checked.If you find that the temperature High
>>>> in a period of time,an interrupt is generated to the processor
>>>> down-measures taken;if the temperature over a period of time High,
>>>> the resulting TSHUT gave CRU module,let it reset the entire chip,
>>>> or via GPIO give PMIC.
>>>>
>>>> Signed-off-by: zhaoyifeng <zyf@rock-chips.com>
> I forgot to ask, is zhaoyifeng the correct name or is it a nickname?
>
>>>> Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
>>>> ---
>>>>    drivers/thermal/Kconfig            |   9 +
>>>>    drivers/thermal/Makefile           |   1 +
>>>>    drivers/thermal/rockchip_thermal.c | 669 +++++++++++++++++++++++++++++++++++++
>>>>    3 files changed, 679 insertions(+)
>>>>    create mode 100644 drivers/thermal/rockchip_thermal.c
>>>>
>>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>>> index f9a1386..a00aa1e 100644
>>>> --- a/drivers/thermal/Kconfig
>>>> +++ b/drivers/thermal/Kconfig
>>>> @@ -133,6 +133,15 @@ config SPEAR_THERMAL
>>>>    	  Enable this to plug the SPEAr thermal sensor driver into the Linux
>>>>    	  thermal framework.
>>>>    
>>>> +config ROCKCHIP_THERMAL
>>>> +	tristate "Rockchip thermal driver"
>>>> +	depends on ARCH_ROCKCHIP
>>>> +	help
>>>> +	  Support for Temperature Sensor ADC (TS-ADC) found on Rockchip SoCs.
>>>> +	  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 RCAR_THERMAL
>>>>    	tristate "Renesas R-Car thermal driver"
>>>>    	depends on ARCH_SHMOBILE || COMPILE_TEST
>>>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>>>> index de0636a..b48b817 100644
>>>> --- a/drivers/thermal/Makefile
>>>> +++ b/drivers/thermal/Makefile
>>>> @@ -19,6 +19,7 @@ thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
>>>>    
>>>>    # platform thermal drivers
>>>>    obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
>>>> +obj-$(CONFIG_ROCKCHIP_THERMAL) 	+= rockchip_thermal.o
>>>>    obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
>>>>    obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
>>>>    obj-y				+= samsung/
>>>> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
>>>> new file mode 100644
>>>> index 0000000..011f387
>>>> --- /dev/null
>>>> +++ b/drivers/thermal/rockchip_thermal.c
>>>> @@ -0,0 +1,669 @@
>>>> +/*
>>>> + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
>>>> + *
>>>> + * 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/clk.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/of_irq.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/regulator/consumer.h>
>>>> +#include <linux/cpu_cooling.h>
>>>> +#include "thermal_core.h"
>>> Why do you need thermal_core.h here? Wouldn't linux/thermal.h be
>>> sufficient?
>>>
>> yes, I will use linux/thermal.h.
>>>> +
>>>> +enum rockchip_thermal_trip {
>>>> +	ROCKCHIP_TRIP_PASSIVE,
>>>> +	ROCKCHIP_TRIP_CRITICAL,
>>>> +	ROCKCHIP_TRIP_NUM,
>>>> +};
>>>> +
>>> Why do you need your own trip types?
>>>
>>>> +struct rockchip_thermal_data {
>>>> +	const struct rockchip_tsadc_platform_data *pdata;
>>>> +	struct thermal_zone_device *tz;
>>>> +	struct thermal_cooling_device *cdev;
>>>> +	enum thermal_device_mode mode;
>>>> +	void __iomem *regs;
>>>> +
>>>> +	signed long temp_passive;
>>>> +	signed long temp_critical;
>>>> +	signed long temp_force_shut;
>>>> +	signed long alarm_temp;
>>>> +	signed long last_temp;
>>>> +	bool irq_enabled;
>>>> +	int irq;
>>>> +	struct clk *clk;
>>>> +	struct clk *pclk;
>>>> +};
>>>> +
>>>> +struct rockchip_tsadc_platform_data {
>>>> +	u8 irq_en;
>>>> +	signed long temp_passive;
>>>> +	signed long temp_critical;
>>>> +	signed long temp_force_shut;
>>>> +	int passive_delay;
>>>> +	int polling_delay;
>>>> +
>>>> +	int (*irq_handle)(void __iomem *reg);
>>>> +	int (*initialize)(void __iomem *reg, signed long temp_force_shut);
>>>> +	int (*control)(void __iomem *reg, bool on);
>>>> +	u32 (*code_to_temp)(int temp);
>>>> +	u32 (*temp_to_code)(int temp);
>>>> +	void (*set_alarm_temp)(void __iomem *regs, signed long temp);
>>>> +};
>>>> +
>>>> +/*TSADC V2 Sensor info define:*/
>>>> +#define TSADCV2_AUTO_CON			0x04
>>>> +#define TSADCV2_INT_EN				0x08
>>>> +#define TSADCV2_INT_PD				0x0c
>>>> +#define TSADCV2_DATA1				0x24
>>>> +#define TSADCV2_COMP1_INT			0x34
>>>> +#define TSADCV2_COMP1_SHUT			0x44
>>>> +#define TSADCV2_AUTO_PERIOD			0x68
>>>> +#define TSADCV2_AUTO_PERIOD_HT			0x6c
>>>> +
>>>> +#define TSADCV2_AUTO_SRC1_EN			(1 << 5)
>>>> +#define TSADCV2_AUTO_EN				(1 << 0)
>>>> +#define TSADCV2_AUTO_DISABLE			~(1 << 0)
>>>> +#define TSADCV2_AUTO_STAS_BUSY			(1 << 16)
>>>> +#define TSADCV2_AUTO_STAS_BUSY_MASK		(1 << 16)
>>>> +#define TSADCV2_SHUT_2GPIO_SRC1_EN		(1 << 5)
>>>> +#define TSADCV2_INT_SRC1_EN			(1 << 1)
>>>> +#define TSADCV2_SHUT_SRC1_STATUS		(1 << 5)
>>>> +#define TSADCV2_INT_SRC1_STATUS			(1 << 1)
>>>> +
>>> The above bits can be defined with BIT() macro, right?
>> Yes. The Bit() will be more resonable..
>>>    Something like:
>>> +#define TSADCV2_INT_SRC1_STATUS			BIT(1)
>>>
>>>
>>>> +#define TSADCV2_DATA_MASK			0xfff
>>>> +#define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
>>>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
>>>> +#define TSADCV2_HIGHT_INT_DEBOUNCE_TIME		0x0a
>>>> +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME	0x0a
>>>> +#define TSADCV2_AUTO_PERIOD_TIME		0x03e8
>>>> +#define TSADCV2_AUTO_PERIOD_HT_TIME		0x64
>>>> +
>>>> +struct tsadc_table {
>>>> +	int code;
>>>> +	int temp;
>>>> +};
>>>> +
>>>> +static const struct tsadc_table v2_code_table[] = {
>>>> +	{TSADCV2_DATA_MASK, -40},
>>>> +	{3800, -40},
>>>> +	{3792, -35},
>>>> +	{3783, -30},
>>>> +	{3774, -25},
>>>> +	{3765, -20},
>>>> +	{3756, -15},
>>>> +	{3747, -10},
>>>> +	{3737, -5},
>>>> +	{3728, 0},
>>>> +	{3718, 5},
>>>> +	{3708, 10},
>>>> +	{3698, 15},
>>>> +	{3688, 20},
>>>> +	{3678, 25},
>>>> +	{3667, 30},
>>>> +	{3656, 35},
>>>> +	{3645, 40},
>>>> +	{3634, 45},
>>>> +	{3623, 50},
>>>> +	{3611, 55},
>>>> +	{3600, 60},
>>>> +	{3588, 65},
>>>> +	{3575, 70},
>>>> +	{3563, 75},
>>>> +	{3550, 80},
>>>> +	{3537, 85},
>>>> +	{3524, 90},
>>>> +	{3510, 95},
>>>> +	{3496, 100},
>>>> +	{3482, 105},
>>>> +	{3467, 110},
>>>> +	{3452, 115},
>>>> +	{3437, 120},
>>>> +	{3421, 125},
>>>> +	{0, 125},
>>>> +};
>>>> +
>>>> +static int rk_tsadcv2_irq_handle(void __iomem *regs)
>>>> +{
>>>> +	u32 val;
>>>> +
>>>> +	val = readl_relaxed(regs + TSADCV2_INT_PD);
>>>> +	writel_relaxed(val & ~(1 << 8), regs + TSADCV2_INT_PD);
>>> Why do you need to clear bit 8? Why hardcoded?
>> The bit 8 set 0 to clear the interrupt.
>>
> Would it make sense to create a macro for this?
>
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static u32 rk_tsadcv2_temp_to_code(int temp)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>>>> +		if (temp <= v2_code_table[i].temp && temp >
>>>> +		    v2_code_table[i - 1].temp)
>>>> +			return v2_code_table[i].code;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static u32 rk_tsadcv2_code_to_temp(int code)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
>>>> +		if (code <= v2_code_table[i].code && code >
>>>> +		    v2_code_table[i + 1].code){
>>>> +			return v2_code_table[i].temp;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> I know the table is not something too big, but considering it is ordered
>>> by either ADC value code or by temp, at least one of the above searching function
>>> may be more efficient, right?

In general,I should use dichotomy,Say, as the follows:

static u32 rk_tsadcv2_temp_to_code(int temp)
{
   int low = 0, high, mid;
   high =  ARRAY_SIZE(v2_code_table) - 1;
   ......

     while(high >= low) {
             mid = (high + low)/2;
             if (v2_code_table[mid].temp == temp)
                 return v2_code_table[mid].code;
             if (v2_code_table[mid].temp > temp)
                 high = mid - 1;
             if (v2_code_table[mid].temp < temp)
                 low = mid + 1;
     }
}

but, I better like to use the follows than the about.

static u32 rk_tsadcv2_temp_to_code(int temp)
{
     int i;

     for (i = 0; i < ARRAY_SIZE(v2_code_table) - 1; i++) {
         if (temp <= v2_code_table[i].temp)
             return v2_code_table[i].code;
     }

     return 0;
}

Do you agree?

I sent Patch v5,you can review again,if you are available.
>> Yes, use the point will be more efficient.
>>>> +
>>>> +static int rk_tsadcv2_initialize(void __iomem *regs,
>>>> +				 signed long temp_force_shut)
>>>> +{
>>>> +	int shutdown_value;
>>>> +
>>>> +	shutdown_value = rk_tsadcv2_temp_to_code(temp_force_shut);
>>>> +	/* Enable measurements at ~ 10 Hz */
>>> Does it leave the sampling clock at 10Hz?
>> yes.
> ok
>
>
>>> Is this clock exposed via
>>> clock framework?
>> The clock is divided by data->clk.
> ok
>
>>>> +	writel_relaxed(0, regs + TSADCV2_AUTO_CON);
>>>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
>>>> +	writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, regs +
>>>> +		       TSADCV2_AUTO_PERIOD_HT);
>>>> +	writel_relaxed(shutdown_value, regs + TSADCV2_COMP1_SHUT);
>>>> +	writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_TIME, regs +
>>>> +		       TSADCV2_HIGHT_INT_DEBOUNCE);
>>>> +	writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_TIME, regs +
>>>> +		       TSADCV2_HIGHT_TSHUT_DEBOUNCE);
>>>> +	writel_relaxed(TSADCV2_SHUT_2GPIO_SRC1_EN | TSADCV2_INT_SRC1_EN, regs +
>>>> +		       TSADCV2_INT_EN);
>>>> +	writel_relaxed(TSADCV2_AUTO_SRC1_EN | TSADCV2_AUTO_EN, regs +
>>>> +		       TSADCV2_AUTO_CON);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rk_tsadcv2_control(void __iomem *regs, bool on)
>>>> +{
>>>> +	u32 val;
>>>> +
>>>> +	if (on) {
>>>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>>>> +		writel_relaxed(val | TSADCV2_AUTO_EN, regs + TSADCV2_AUTO_CON);
>>>> +	} else {
>>>> +		val = readl_relaxed(regs + TSADCV2_AUTO_CON);
>>>> +		writel_relaxed(val & TSADCV2_AUTO_DISABLE,
>>>> +			       regs + TSADCV2_AUTO_CON);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void rk_tsadcv2_alarm_temp(void __iomem *regs, signed long alarm_temp)
>>>> +{
>>>> +	int alarm_value;
>>>> +
>>>> +	alarm_value = rk_tsadcv2_temp_to_code(alarm_temp);
>>>> +	writel_relaxed(alarm_value, regs + TSADCV2_COMP1_INT);
>>>> +}
>>>> +
>>>> +struct rockchip_tsadc_platform_data const rk3288_tsadc_data = {
>>>> +	.irq_en = 1,
>>>> +	.temp_passive = 85000,
>>>> +	.temp_critical = 100000,
>>>> +	.temp_force_shut = 120000,
>>>> +	.passive_delay = 2000,
>>>> +	.polling_delay = 1000,
>>>> +	.irq_handle = rk_tsadcv2_irq_handle,
>>>> +	.initialize = rk_tsadcv2_initialize,
>>>> +	.control = rk_tsadcv2_control,
>>>> +	.code_to_temp = rk_tsadcv2_code_to_temp,
>>>> +	.temp_to_code = rk_tsadcv2_temp_to_code,
>>>> +	.set_alarm_temp = rk_tsadcv2_alarm_temp,
>>>> +};
>>> shall the above struct be also static?
>> OK.
>>>> +
>>>> +static const struct of_device_id of_rockchip_thermal_match[] = {
>>>> +	{
>>>> +		.compatible = "rockchip,rk3288-tsadc",
>>>> +		.data = (void *)&rk3288_tsadc_data,
>>>> +	},
>>>> +	{ /* end */ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
>>>> +
>>>> +static void rockchip_set_alarm_temp(struct rockchip_thermal_data *data,
>>>> +				    signed long alarm_temp)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	data->alarm_temp = alarm_temp;
>>>> +	if (p_tsadc_data->set_alarm_temp)
>>>> +		p_tsadc_data->set_alarm_temp(data->regs, alarm_temp);
>>>> +}
>>>> +
>>>> +static int rockchip_get_temp(struct thermal_zone_device *tz,
>>>> +			     unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +	u32 val;
>>>> +
>>>> +	val = readl_relaxed(data->regs + TSADCV2_DATA1);
>>>> +	*temp = p_tsadc_data->code_to_temp(val);
>>>> +
>>>> +	/* Update alarm value to next higher trip point */
>>>> +	if (data->alarm_temp == data->temp_passive && *temp >=
>>>> +	    data->temp_passive)
>>>> +		rockchip_set_alarm_temp(data, data->temp_critical);
>>>> +
>>>> +	if (data->alarm_temp == data->temp_critical && *temp <
>>>> +	    data->temp_passive) {
>>>> +		rockchip_set_alarm_temp(data, data->temp_passive);
>>>> +		dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
>>>> +			data->alarm_temp / 1000);
>>>> +	}
>>>> +
>>>> +	if (*temp != data->last_temp) {
>>>> +		dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
>>>> +		data->last_temp = *temp;
>>>> +	}
>>>> +
>>>> +	/* Reenable alarm IRQ if temperature below alarm temperature */
>>>> +	if (!data->irq_enabled && *temp < data->alarm_temp) {
>>>> +		data->irq_enabled = true;
>>>> +		enable_irq(data->irq);
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_initialize(struct rockchip_thermal_data *data)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (p_tsadc_data->initialize)
>>>> +		p_tsadc_data->initialize(data->regs, data->temp_force_shut);
>>>> +	rockchip_set_alarm_temp(data, data->temp_passive);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void rockchip_thermal_control(struct rockchip_thermal_data *data,
>>>> +				     bool on)
>>>> +{
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (p_tsadc_data->control)
>>>> +		p_tsadc_data->control(data->regs, on);
>>>> +
>>>> +	if (on) {
>>>> +		data->irq_enabled = true;
>>>> +		data->mode = THERMAL_DEVICE_ENABLED;
>>>> +	} else {
>>>> +		data->irq_enabled = false;
>>>> +		data->mode = THERMAL_DEVICE_DISABLED;
>>>> +	}
>>>> +}
>>>> +
>>>> +static int rockchip_get_mode(struct thermal_zone_device *tz,
>>>> +			     enum thermal_device_mode *mode)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*mode = data->mode;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_set_mode(struct thermal_zone_device *tz,
>>>> +			     enum thermal_device_mode mode)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	if (mode == THERMAL_DEVICE_ENABLED) {
>>>> +		tz->polling_delay = p_tsadc_data->polling_delay;
>>>> +		tz->passive_delay = p_tsadc_data->passive_delay;
>>>> +		if (!data->irq_enabled) {
>>>> +			data->irq_enabled = true;
>>>> +			enable_irq(data->irq);
>>>> +		}
>>>> +	} else {
>>>> +		tz->polling_delay = 0;
>>>> +		tz->passive_delay = 0;
>>>> +		if (data->irq_enabled) {
>>>> +			disable_irq(data->irq);
>>>> +			data->irq_enabled = false;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	data->mode = mode;
>>>> +	thermal_zone_device_update(tz);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_trip_type(struct thermal_zone_device *tz, int trip,
>>>> +				  enum thermal_trip_type *type)
>>>> +{
>>>> +	*type = (trip == ROCKCHIP_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
>>>> +		 THERMAL_TRIP_CRITICAL;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_crit_temp(struct thermal_zone_device *tz,
>>>> +				  unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*temp = data->temp_critical;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_get_trip_temp(struct thermal_zone_device *tz, int trip,
>>>> +				  unsigned long *temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	*temp = (trip == ROCKCHIP_TRIP_PASSIVE) ? data->temp_passive :
>>>> +		 data->temp_critical;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_set_trip_temp(struct thermal_zone_device *tz, int trip,
>>>> +				  unsigned long temp)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = tz->devdata;
>>>> +
>>>> +	if (trip == ROCKCHIP_TRIP_CRITICAL)
>>>> +		return -EPERM;
>>>> +
>>>> +	data->temp_passive = temp;
>>>> +	rockchip_set_alarm_temp(data, temp);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_bind(struct thermal_zone_device *tz,
>>>> +			 struct thermal_cooling_device *cdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = thermal_zone_bind_cooling_device(tz, ROCKCHIP_TRIP_PASSIVE, cdev,
>>>> +					       THERMAL_NO_LIMIT,
>>>> +					       THERMAL_NO_LIMIT);
>>>> +	if (ret) {
>>>> +		dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>>>> +			tz->type, cdev->type, ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_unbind(struct thermal_zone_device *tz,
>>>> +			   struct thermal_cooling_device *cdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = thermal_zone_unbind_cooling_device(tz,
>>>> +						 ROCKCHIP_TRIP_PASSIVE, cdev);
>>>> +	if (ret) {
>>>> +		dev_err(&tz->device,
>>>> +			"unbinding zone %s with cdev %s failed:%d\n", tz->type,
>>>> +			cdev->type, ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> The method of binding and unbinding used above requires you to check if
>>> you are binding to the right cdev. If in your system you register more
>>> than one cdev, say someone loads the power supply core, which in turns
>>> register a cooling device for charging, your thermal zone will bind it
>>> to TRIP_PASSIVE. It will happen to any cooling device that eventually
>>> gets registered to the thermal framework. Is that the desired outcome?
>> Yes,I will use the generic trip points in the dts and fix it in the
>> thermal driver.
> great
>
>>> If not, you may want to compare the paramenter cdev to your data->cdev.
>>>
>>>> +
>>>> +static struct thermal_zone_device_ops rockchip_tz_ops = {
>>>> +	.bind = rockchip_bind,
>>>> +	.unbind = rockchip_unbind,
>>>> +	.get_temp = rockchip_get_temp,
>>>> +	.get_mode = rockchip_get_mode,
>>>> +	.set_mode = rockchip_set_mode,
>>>> +	.get_trip_type = rockchip_get_trip_type,
>>>> +	.get_trip_temp = rockchip_get_trip_temp,
>>>> +	.get_crit_temp = rockchip_get_crit_temp,
>>>> +	.set_trip_temp = rockchip_set_trip_temp,
>>>> +};
>>>> +
>>>> +static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = data;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data = data->pdata;
>>>> +
>>>> +	dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
>>>> +		data->alarm_temp / 1000);
>>>> +
>>>> +	if (p_tsadc_data->irq_en && p_tsadc_data->irq_handle)
>>>> +		p_tsadc_data->irq_handle(data->regs);
>>>> +
>>>> +	thermal_zone_device_update(data->tz);
>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_probe(struct platform_device *pdev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data;
>>>> +	const struct rockchip_tsadc_platform_data *p_tsadc_data;
>>>> +	struct cpumask clip_cpus;
>>>> +	struct resource *res;
>>>> +	const struct of_device_id *match;
>>>> +	int ret, temp;
>>>> +
>>>> +	data = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data),
>>>> +			    GFP_KERNEL);
>>>> +	if (!data)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	data->regs = devm_ioremap_resource(&pdev->dev, res);
>>>> +	if (IS_ERR(data->regs)) {
>>>> +		dev_err(&pdev->dev, "Could not get tsadc source, %p\n",
>>>> +			data->regs);
>>>> +		return PTR_ERR(data->regs);
>>>> +	}
>>>> +
>>>> +	match = of_match_node(of_rockchip_thermal_match, pdev->dev.of_node);
>>>> +	if (!match)
>>>> +		return -ENXIO;
>>>> +	data->pdata = (const struct rockchip_tsadc_platform_data *)match->data;
>>>> +	if (!data->pdata)
>>>> +		return -EINVAL;
>>>> +	p_tsadc_data = data->pdata;
>>>> +
>>>> +	data->clk = devm_clk_get(&pdev->dev, "tsadc");
>>>> +	if (IS_ERR(data->clk)) {
>>>> +		dev_err(&pdev->dev, "failed to get tsadc clock\n");
>>>> +		return PTR_ERR(data->clk);
>>>> +	}
>>>> +
>>>> +	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
>>>> +	if (IS_ERR(data->pclk)) {
>>>> +		dev_err(&pdev->dev, "failed to get tsadc pclk\n");
>>>> +		return PTR_ERR(data->pclk);
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	* Use a default of 10KHz for the converter clock.
>>>> +	* This may become user-configurable in the future.
>>>> +	*/
>>>> +	ret = clk_set_rate(data->clk, 10000);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to set tsadc clk rate, %d\n", ret);
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(data->clk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to enable converter clock\n");
>>>> +		goto err_clk;
>>>> +	}
>>>> +
>>>> +	ret = clk_prepare_enable(data->pclk);
>>>> +	if (ret < 0) {
>>>> +		dev_err(&pdev->dev, "failed to enable pclk\n");
>>>> +		goto err_pclk;
>>>> +	}
>>>> +
>>>> +	platform_set_drvdata(pdev, data);
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "passive-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default passive temp property in the DT.\n");
>>>> +		data->temp_passive = p_tsadc_data->temp_passive;
>>>> +	} else {
>>>> +		data->temp_passive = temp;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "critical-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default critical temp property in the DT.\n");
>>>> +		data->temp_critical = p_tsadc_data->temp_critical;
>>>> +	} else {
>>>> +		data->temp_critical = temp;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(pdev->dev.of_node, "force-shut-temp", &temp)) {
>>>> +		dev_warn(&pdev->dev,
>>>> +			 "Missing default force shut down temp property in the DT.\n");
>>>> +		data->temp_force_shut = p_tsadc_data->temp_force_shut;
>>>> +	} else {
>>>> +		data->temp_force_shut = temp;
>>>> +	}
>>>> +
>>>> +	cpumask_set_cpu(0, &clip_cpus);
>>>> +	data->cdev = of_cpufreq_cooling_register(pdev->dev.of_node, &clip_cpus);
>>>> +	if (IS_ERR(data->cdev)) {
>>>> +		dev_err(&pdev->dev, "failed to register cpufreq cooling device\n");
>>>> +		goto disable_clk;
>>>> +	}
>>>> +
>>>> +	data->tz = thermal_zone_device_register("rockchip_thermal",
>>>> +						ROCKCHIP_TRIP_NUM,
>>>> +						0, data,
>>>> +						&rockchip_tz_ops, NULL,
>>>> +						p_tsadc_data->passive_delay,
>>>> +						p_tsadc_data->polling_delay);
>>>> +
>>>> +	if (IS_ERR(data->tz)) {
>>>> +		dev_err(&pdev->dev, "failed to register thermal zone device\n");
>>>> +		goto fail_cpufreq_register;
>>>> +	}
>>>> +
>>>> +	if (p_tsadc_data->irq_en) {
>>>> +		data->irq = platform_get_irq(pdev, 0);
>>>> +		if (data->irq < 0) {
>>>> +			dev_err(&pdev->dev, "no irq resource?\n");
>>>> +			goto fail_irq;
>>>> +		}
>>>> +
>>>> +		ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
>>>> +				rockchip_thermal_alarm_irq_thread,
>>>> +				IRQF_ONESHOT, "rockchip_thermal", data);
>>>> +		if (ret < 0) {
>>>> +			dev_err(&pdev->dev,
>>>> +				"failed to request tsadc irq: %d\n", ret);
>>>> +			goto fail_thermal_unregister;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	rockchip_thermal_initialize(data);
>>>> +	rockchip_thermal_control(data, true);
>>>> +
>>>> +	return 0;
>>>> +
>>>> +fail_thermal_unregister:
>>>> +	thermal_zone_device_unregister(data->tz);
>>>> +fail_irq:
>>>> +fail_cpufreq_register:
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +disable_clk:
>>>> +err_pclk:
>>>> +	clk_disable_unprepare(data->pclk);
>>>> +err_clk:
>>>> +	clk_disable_unprepare(data->clk);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_control(data, false);
>>>> +
>>>> +	thermal_zone_device_unregister(data->tz);
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +	cpufreq_cooling_unregister(data->cdev);
>>>> +
>>> The above call is duplicated.
>> OK.
>>>> +	clk_disable_unprepare(data->clk);
>>>> +	clk_disable_unprepare(data->pclk);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int rockchip_thermal_suspend(struct device *dev)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_control(data, false);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int rockchip_thermal_resume(struct device *dev)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct rockchip_thermal_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +	rockchip_thermal_initialize(data);
>>>> +	rockchip_thermal_control(data, true);
>>>> +
>>>> +	return 0;
>>>> +}
>>> Would you need to manage your clocks too in the suspend resume path
>>> (data->clk and data->pclk)?
>> yes.
>> Usually,it's need disable to save power.
> Yes, that's my point. Please consider handling clocks to improve power
> savings.
>
>>>> +#endif
>>>> +
>>>> +static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
>>>> +			 rockchip_thermal_suspend, rockchip_thermal_resume);
>>>> +
>>>> +static struct platform_driver rockchip_thermal_driver = {
>>>> +	.driver = {
>>>> +		   .name = "rockchip-thermal",
>>>> +		   .owner = THIS_MODULE,
>>>> +		   .pm = &rockchip_thermal_pm_ops,
>>>> +		   .of_match_table = of_rockchip_thermal_match,
>>>> +		   },
>>>> +	.probe = rockchip_thermal_probe,
>>>> +	.remove = rockchip_thermal_remove,
>>>> +};
>>>> +
>>>> +module_platform_driver(rockchip_thermal_driver);
>>>> +
>>>> +MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver");
>>>> +MODULE_AUTHOR("Rockchip, Inc.");
>>>> +MODULE_LICENSE("GPL");
>>> Your file header states GPL version two. Thus I suppose you meant:
>>> +MODULE_LICENSE("GPL v2");
>>>
>>> right?
>>>
>>> Check include/linux/module.h for further clarifications.
>> But I think the  "GPL"  is support for thr GNU Public License v2 or later.
> Exactly, if you intend to support v3, then it is fine. But your code
> header states only V2.
>
>> I will fix GPL v2 if I get it wrong.
> If your license is GPLv2 only as mentioned in your header, please use 'GPL
> v2' tag.
>
> Cheers,
>
>>>> +MODULE_ALIAS("platform:rockchip-thermal");
>>>> -- 
>>>> 1.9.1
>>>>
>>>>
>>> BR,
>>>
>>> Eduardo Valentin
>>>
>>>
>>>
>> -- 
>> Best regards,
>> Caesar
>>
>>
>
>

-- 
Best regards,
Caesar

^ permalink raw reply	[flat|nested] 65+ messages in thread

end of thread, other threads:[~2014-09-17  7:29 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-03  2:10 [PATCH v4 0/4] Rockchip soc thermal driver Caesar Wang
2014-09-03  2:10 ` Caesar Wang
2014-09-03  2:10 ` [PATCH v4 1/4] thermal: rockchip: add driver for thermal Caesar Wang
2014-09-03  2:10   ` Caesar Wang
2014-08-30 20:09   ` Eduardo Valentin
2014-08-30 20:09     ` Eduardo Valentin
2014-09-10  4:39     ` Caesar Wang
2014-09-10  4:39       ` Caesar Wang
2014-09-10 12:46       ` Eduardo Valentin
2014-09-10 12:46         ` Eduardo Valentin
2014-09-10 13:21         ` Caesar Wang
2014-09-10 13:21           ` Caesar Wang
2014-09-10 13:21           ` Caesar Wang
2014-09-17  7:29         ` Caesar Wang
2014-09-17  7:29           ` Caesar Wang
2014-09-04 17:06   ` Dmitry Torokhov
2014-09-04 17:06     ` Dmitry Torokhov
2014-09-05  0:33     ` Caesar Wang
2014-09-05  0:33       ` Caesar Wang
2014-09-03  2:10 ` [PATCH v4 2/4] dt-bindings: document Rockchip thermal Caesar Wang
2014-09-03  2:10   ` Caesar Wang
2014-09-03  8:07   ` Heiko Stübner
2014-09-03  8:07     ` Heiko Stübner
2014-09-04  1:02     ` Caesar Wang
2014-09-04  1:02       ` Caesar Wang
2014-09-09  2:27       ` Zhang Rui
2014-09-09  2:27         ` Zhang Rui
2014-09-09 11:35         ` Heiko Stübner
2014-09-09 11:35           ` Heiko Stübner
2014-09-09 11:35           ` Heiko Stübner
2014-09-09 15:09           ` Eduardo Valentin
2014-09-09 15:09             ` Eduardo Valentin
2014-09-09 15:09             ` Eduardo Valentin
2014-09-10  1:02             ` Zhang Rui
2014-09-10  1:02               ` Zhang Rui
2014-09-10  1:14               ` edubezval
2014-09-10  1:14                 ` edubezval at gmail.com
2014-09-10  7:24                 ` Heiko Stübner
2014-09-10  7:24                   ` Heiko Stübner
2014-09-10  7:24                   ` Heiko Stübner
2014-09-11  2:36                   ` Zhang Rui
2014-09-11  2:36                     ` Zhang Rui
2014-09-11  2:36                     ` Zhang Rui
2014-09-11 12:18                     ` Eduardo Valentin
2014-09-11 12:18                       ` Eduardo Valentin
2014-09-11 12:18                       ` Eduardo Valentin
2014-09-11 12:32                       ` Arnd Bergmann
2014-09-11 12:32                         ` Arnd Bergmann
2014-09-11 15:53                         ` Eduardo Valentin
2014-09-11 15:53                           ` Eduardo Valentin
2014-09-16  7:23                           ` Zhang Rui
2014-09-16  7:23                             ` Zhang Rui
2014-09-16  7:45                           ` Zhang Rui
2014-09-16  7:45                             ` Zhang Rui
2014-09-03  2:10 ` [PATCH v4 3/4] ARM: dts: add main Thermal info to rk3288 Caesar Wang
2014-09-03  2:10   ` Caesar Wang
2014-09-09 11:37   ` Heiko Stübner
2014-09-09 11:37     ` Heiko Stübner
2014-09-10  2:49     ` Caesar Wang
2014-09-10  2:49       ` Caesar Wang
2014-09-11 13:58       ` Heiko Stübner
2014-09-11 13:58         ` Heiko Stübner
2014-09-11 13:58         ` Heiko Stübner
2014-09-03  2:10 ` [PATCH v4 4/4] ARM: dts: enable Thermal on rk3288-evb board Caesar Wang
2014-09-03  2:10   ` Caesar Wang

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.