diff mbox

[v3,14/16] thermal: samsung: core: Exynos TMU rework to use device tree for configuration

Message ID 1421242874-3425-15-git-send-email-l.majewski@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Lukasz Majewski Jan. 14, 2015, 1:41 p.m. UTC
This patch brings support for providing configuration via device tree.
Previously this data has been hardcoded in the exynos_tmu_data.c file.
Such approach was not scalable and very often required copying the whole
data.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
---
Changes for v2:
- Adjust exynos_tmu.c code to the newest ti-soc-thermal repository
- Usage of of-thermal.c exported trip points table
Changes for v3:
- Adding exynos_of_get_soc_type() method to set SOC type from device's
  compatible string
- "samsung,tmu_" prefix for TMU specific properties has been added

---
 drivers/thermal/samsung/Makefile     |   2 -
 drivers/thermal/samsung/exynos_tmu.c | 345 +++++++++++++++++++++++------------
 drivers/thermal/samsung/exynos_tmu.h |  53 +-----
 3 files changed, 226 insertions(+), 174 deletions(-)

Comments

Eduardo Valentin Jan. 14, 2015, 6:46 p.m. UTC | #1
On Wed, Jan 14, 2015 at 02:41:12PM +0100, Lukasz Majewski wrote:
> This patch brings support for providing configuration via device tree.
> Previously this data has been hardcoded in the exynos_tmu_data.c file.
> Such approach was not scalable and very often required copying the whole
> data.
> 
> Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> ---
> Changes for v2:
> - Adjust exynos_tmu.c code to the newest ti-soc-thermal repository
> - Usage of of-thermal.c exported trip points table
> Changes for v3:
> - Adding exynos_of_get_soc_type() method to set SOC type from device's
>   compatible string
> - "samsung,tmu_" prefix for TMU specific properties has been added
> 
> ---
>  drivers/thermal/samsung/Makefile     |   2 -
>  drivers/thermal/samsung/exynos_tmu.c | 345 +++++++++++++++++++++++------------
>  drivers/thermal/samsung/exynos_tmu.h |  53 +-----
>  3 files changed, 226 insertions(+), 174 deletions(-)
> 
> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
> index c09d830..1e47d0d 100644
> --- a/drivers/thermal/samsung/Makefile
> +++ b/drivers/thermal/samsung/Makefile
> @@ -3,5 +3,3 @@
>  #
>  obj-$(CONFIG_EXYNOS_THERMAL)			+= exynos_thermal.o
>  exynos_thermal-y				:= exynos_tmu.o
> -exynos_thermal-y				+= exynos_tmu_data.o

Can this makefile change be part of the patch that removes
exynos_tmu_data.c?

> -exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE)	+= exynos_thermal_common.o

Can this makefile change be part of the patch that removes
exynos_thermal_common.c?

> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index ae30f6a..633a9e2 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -1,6 +1,10 @@
>  /*
>   * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit)
>   *
> + *  Copyright (C) 2014 Samsung Electronics
> + *  Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> + *  Lukasz Majewski <l.majewski@samsung.com>
> + *
>   *  Copyright (C) 2011 Samsung Electronics
>   *  Donggeun Kim <dg77.kim@samsung.com>
>   *  Amit Daniel Kachhap <amit.kachhap@linaro.org>
> @@ -31,8 +35,8 @@
>  #include <linux/platform_device.h>
>  #include <linux/regulator/consumer.h>
>  
> -#include "exynos_thermal_common.h"
>  #include "exynos_tmu.h"
> +#include "../thermal_core.h"
>  
>  /* Exynos generic registers */
>  #define EXYNOS_TMU_REG_TRIMINFO		0x0
> @@ -115,6 +119,7 @@
>  #define EXYNOS5440_TMU_TH_RISE4_SHIFT		24
>  #define EXYNOS5440_EFUSE_SWAP_OFFSET		8
>  
> +#define MCELSIUS	1000
>  /**
>   * struct exynos_tmu_data : A structure to hold the private data of the TMU
>  	driver
> @@ -150,7 +155,8 @@ struct exynos_tmu_data {
>  	struct clk *clk, *clk_sec;
>  	u8 temp_error1, temp_error2;
>  	struct regulator *regulator;
> -	struct thermal_sensor_conf *reg_conf;
> +	struct thermal_zone_device *tzd;
> +
>  	int (*tmu_initialize)(struct platform_device *pdev);
>  	void (*tmu_control)(struct platform_device *pdev, bool on);
>  	int (*tmu_read)(struct exynos_tmu_data *data);
> @@ -159,6 +165,33 @@ struct exynos_tmu_data {
>  	void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
>  };
>  
> +static void exynos_report_trigger(struct exynos_tmu_data *p)
> +{
> +	char data[10], *envp[] = { data, NULL };
> +	struct thermal_zone_device *tz = p->tzd;
> +	unsigned long temp;
> +	unsigned int i;
> +
> +	if (!p) {
> +		pr_err("Wrong temperature configuration data\n");
> +		return;
> +	}
> +
> +	thermal_zone_device_update(tz);
> +
> +	mutex_lock(&tz->lock);
> +	/* Find the level for which trip happened */
> +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> +		tz->ops->get_trip_temp(tz, i, &temp);
> +		if (tz->last_temperature < temp)
> +			break;
> +	}
> +
> +	snprintf(data, sizeof(data), "%u", i);
> +	kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, envp);
> +	mutex_unlock(&tz->lock);
> +}
> +
>  /*
>   * TMU treats temperature as a mapped temperature code.
>   * The temperature is converted differently depending on the calibration type.
> @@ -234,14 +267,25 @@ static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info)
>  
>  static u32 get_th_reg(struct exynos_tmu_data *data, u32 threshold, bool falling)
>  {
> -	struct exynos_tmu_platform_data *pdata = data->pdata;
> +	struct thermal_zone_device *tz = data->tzd;
> +	const struct thermal_trip * const trips =
> +		of_thermal_get_trip_points(tz);
> +	unsigned long temp;
>  	int i;
>  
> -	for (i = 0; i < pdata->non_hw_trigger_levels; i++) {
> -		u8 temp = pdata->trigger_levels[i];
> +	if (!trips) {
> +		pr_err("%s: Cannot get trip points from of-thermal.c!\n",
> +		       __func__);
> +		return 0;
> +	}
> +
> +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> +		if (trips[i].type == THERMAL_TRIP_CRITICAL)
> +			continue;
>  
> +		temp = trips[i].temperature / MCELSIUS;
>  		if (falling)
> -			temp -= pdata->threshold_falling;
> +			temp -= (trips[i].hysteresis / MCELSIUS);
>  		else
>  			threshold &= ~(0xff << 8 * i);
>  
> @@ -305,9 +349,19 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
>  static int exynos4210_tmu_initialize(struct platform_device *pdev)
>  {
>  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> -	struct exynos_tmu_platform_data *pdata = data->pdata;
> -	unsigned int status;
> +	struct thermal_zone_device *tz = data->tzd;
> +	const struct thermal_trip * const trips =
> +		of_thermal_get_trip_points(tz);
>  	int ret = 0, threshold_code, i;
> +	unsigned long reference, temp;
> +	unsigned int status;
> +
> +	if (!trips) {
> +		pr_err("%s: Cannot get trip points from of-thermal.c!\n",
> +		       __func__);
> +		ret = -ENODEV;
> +		goto out;
> +	}
>  
>  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
>  	if (!status) {
> @@ -318,12 +372,19 @@ static int exynos4210_tmu_initialize(struct platform_device *pdev)
>  	sanitize_temp_error(data, readl(data->base + EXYNOS_TMU_REG_TRIMINFO));
>  
>  	/* Write temperature code for threshold */
> -	threshold_code = temp_to_code(data, pdata->threshold);
> +	reference = trips[0].temperature / MCELSIUS;
> +	threshold_code = temp_to_code(data, reference);
> +	if (threshold_code < 0) {
> +		ret = threshold_code;
> +		goto out;
> +	}
>  	writeb(threshold_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
>  
> -	for (i = 0; i < pdata->non_hw_trigger_levels; i++)
> -		writeb(pdata->trigger_levels[i], data->base +
> +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> +		temp = trips[i].temperature / MCELSIUS;
> +		writeb(temp - reference, data->base +
>  		       EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
> +	}
>  
>  	data->tmu_clear_irqs(data);
>  out:
> @@ -333,9 +394,11 @@ out:
>  static int exynos4412_tmu_initialize(struct platform_device *pdev)
>  {
>  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> -	struct exynos_tmu_platform_data *pdata = data->pdata;
> +	const struct thermal_trip * const trips =
> +		of_thermal_get_trip_points(data->tzd);
>  	unsigned int status, trim_info, con, ctrl, rising_threshold;
>  	int ret = 0, threshold_code, i;
> +	unsigned long crit_temp = 0;
>  
>  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
>  	if (!status) {
> @@ -373,17 +436,29 @@ static int exynos4412_tmu_initialize(struct platform_device *pdev)
>  	data->tmu_clear_irqs(data);
>  
>  	/* if last threshold limit is also present */
> -	i = pdata->max_trigger_level - 1;
> -	if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) {
> -		threshold_code = temp_to_code(data, pdata->trigger_levels[i]);
> -		/* 1-4 level to be assigned in th0 reg */
> -		rising_threshold &= ~(0xff << 8 * i);
> -		rising_threshold |= threshold_code << 8 * i;
> -		writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE);
> -		con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
> -		con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> -		writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> +	for (i = 0; i < of_thermal_get_ntrips(data->tzd); i++) {
> +		if (trips[i].type == THERMAL_TRIP_CRITICAL) {
> +			crit_temp = trips[i].temperature;
> +			break;
> +		}
>  	}
> +
> +	if (i == of_thermal_get_ntrips(data->tzd)) {
> +		pr_err("%s: No CRITICAL trip point defined at of-thermal.c!\n",
> +		       __func__);
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	threshold_code = temp_to_code(data, crit_temp / MCELSIUS);
> +	/* 1-4 level to be assigned in th0 reg */
> +	rising_threshold &= ~(0xff << 8 * i);
> +	rising_threshold |= threshold_code << 8 * i;
> +	writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE);
> +	con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
> +	con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> +	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> +
>  out:
>  	return ret;
>  }
> @@ -391,9 +466,9 @@ out:
>  static int exynos5440_tmu_initialize(struct platform_device *pdev)
>  {
>  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> -	struct exynos_tmu_platform_data *pdata = data->pdata;
>  	unsigned int trim_info = 0, con, rising_threshold;
> -	int ret = 0, threshold_code, i;
> +	int ret = 0, threshold_code;
> +	unsigned long crit_temp = 0;
>  
>  	/*
>  	 * For exynos5440 soc triminfo value is swapped between TMU0 and
> @@ -422,9 +497,8 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev)
>  	data->tmu_clear_irqs(data);
>  
>  	/* if last threshold limit is also present */
> -	i = pdata->max_trigger_level - 1;
> -	if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) {
> -		threshold_code = temp_to_code(data, pdata->trigger_levels[i]);
> +	if (!data->tzd->ops->get_crit_temp(data->tzd, &crit_temp)) {
> +		threshold_code = temp_to_code(data, crit_temp / MCELSIUS);
>  		/* 5th level to be assigned in th2 reg */
>  		rising_threshold =
>  			threshold_code << EXYNOS5440_TMU_TH_RISE4_SHIFT;
> @@ -442,7 +516,7 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev)
>  static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
>  {
>  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> -	struct exynos_tmu_platform_data *pdata = data->pdata;
> +	struct thermal_zone_device *tz = data->tzd;
>  	unsigned int con, interrupt_en;
>  
>  	con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));
> @@ -450,10 +524,15 @@ static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
>  	if (on) {
>  		con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
>  		interrupt_en =
> -			pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
> -			pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
> -			pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
> -			pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
> +			(of_thermal_is_trip_valid(tz, 3)
> +			 << EXYNOS_TMU_INTEN_RISE3_SHIFT) |
> +			(of_thermal_is_trip_valid(tz, 2)
> +			 << EXYNOS_TMU_INTEN_RISE2_SHIFT) |
> +			(of_thermal_is_trip_valid(tz, 1)
> +			 << EXYNOS_TMU_INTEN_RISE1_SHIFT) |
> +			(of_thermal_is_trip_valid(tz, 0)
> +			 << EXYNOS_TMU_INTEN_RISE0_SHIFT);
> +
>  		if (data->soc != SOC_ARCH_EXYNOS4210)
>  			interrupt_en |=
>  				interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
> @@ -468,7 +547,7 @@ static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
>  static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
>  {
>  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> -	struct exynos_tmu_platform_data *pdata = data->pdata;
> +	struct thermal_zone_device *tz = data->tzd;
>  	unsigned int con, interrupt_en;
>  
>  	con = get_con_reg(data, readl(data->base + EXYNOS5440_TMU_S0_7_CTRL));
> @@ -476,11 +555,16 @@ static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
>  	if (on) {
>  		con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
>  		interrupt_en =
> -			pdata->trigger_enable[3] << EXYNOS5440_TMU_INTEN_RISE3_SHIFT |
> -			pdata->trigger_enable[2] << EXYNOS5440_TMU_INTEN_RISE2_SHIFT |
> -			pdata->trigger_enable[1] << EXYNOS5440_TMU_INTEN_RISE1_SHIFT |
> -			pdata->trigger_enable[0] << EXYNOS5440_TMU_INTEN_RISE0_SHIFT;
> -		interrupt_en |= interrupt_en << EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
> +			(of_thermal_is_trip_valid(tz, 3)
> +			 << EXYNOS5440_TMU_INTEN_RISE3_SHIFT) |
> +			(of_thermal_is_trip_valid(tz, 2)
> +			 << EXYNOS5440_TMU_INTEN_RISE2_SHIFT) |
> +			(of_thermal_is_trip_valid(tz, 1)
> +			 << EXYNOS5440_TMU_INTEN_RISE1_SHIFT) |
> +			(of_thermal_is_trip_valid(tz, 0)
> +			 << EXYNOS5440_TMU_INTEN_RISE0_SHIFT);
> +		interrupt_en |=
> +			interrupt_en << EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
>  	} else {
>  		con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
>  		interrupt_en = 0; /* Disable all interrupts */
> @@ -489,19 +573,22 @@ static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
>  	writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL);
>  }
>  
> -static int exynos_tmu_read(struct exynos_tmu_data *data)
> +int exynos_get_temp(void *p, long *temp)
>  {
> -	int ret;
> +	struct exynos_tmu_data *data = p;
> +
> +	if (!data)
> +		return -EINVAL;
>  
>  	mutex_lock(&data->lock);
>  	clk_enable(data->clk);
> -	ret = data->tmu_read(data);
> -	if (ret >= 0)
> -		ret = code_to_temp(data, ret);
> +
> +	*temp = code_to_temp(data, data->tmu_read(data)) * MCELSIUS;
> +
>  	clk_disable(data->clk);
>  	mutex_unlock(&data->lock);
>  
> -	return ret;
> +	return 0;
>  }
>  
>  #ifdef CONFIG_THERMAL_EMULATION
> @@ -613,7 +700,7 @@ static void exynos_tmu_work(struct work_struct *work)
>  	if (!IS_ERR(data->clk_sec))
>  		clk_disable(data->clk_sec);
>  
> -	exynos_report_trigger(data->reg_conf);
> +	exynos_report_trigger(data);
>  	mutex_lock(&data->lock);
>  	clk_enable(data->clk);
>  
> @@ -673,55 +760,89 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
>  static const struct of_device_id exynos_tmu_match[] = {
>  	{
>  		.compatible = "samsung,exynos3250-tmu",
> -		.data = &exynos3250_default_tmu_data,
>  	},
>  	{
>  		.compatible = "samsung,exynos4210-tmu",
> -		.data = &exynos4210_default_tmu_data,
>  	},
>  	{
>  		.compatible = "samsung,exynos4412-tmu",
> -		.data = &exynos4412_default_tmu_data,
>  	},
>  	{
>  		.compatible = "samsung,exynos5250-tmu",
> -		.data = &exynos5250_default_tmu_data,
>  	},
>  	{
>  		.compatible = "samsung,exynos5260-tmu",
> -		.data = &exynos5260_default_tmu_data,
>  	},
>  	{
>  		.compatible = "samsung,exynos5420-tmu",
> -		.data = &exynos5420_default_tmu_data,
>  	},
>  	{
>  		.compatible = "samsung,exynos5420-tmu-ext-triminfo",
> -		.data = &exynos5420_default_tmu_data,
>  	},
>  	{
>  		.compatible = "samsung,exynos5440-tmu",
> -		.data = &exynos5440_default_tmu_data,
>  	},
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, exynos_tmu_match);
>  
> -static inline struct  exynos_tmu_platform_data *exynos_get_driver_data(
> -			struct platform_device *pdev, int id)
> +static int exynos_of_get_soc_type(struct device_node *np)
>  {
> -	struct  exynos_tmu_init_data *data_table;
> -	struct exynos_tmu_platform_data *tmu_data;
> -	const struct of_device_id *match;
> +	if (of_device_is_compatible(np, "samsung,exynos3250-tmu"))
> +		return SOC_ARCH_EXYNOS3250;
> +	else if (of_device_is_compatible(np, "samsung,exynos4210-tmu"))
> +		return SOC_ARCH_EXYNOS4210;
> +	else if (of_device_is_compatible(np, "samsung,exynos4412-tmu"))
> +		return SOC_ARCH_EXYNOS4412;
> +	else if (of_device_is_compatible(np, "samsung,exynos5250-tmu"))
> +		return SOC_ARCH_EXYNOS5250;
> +	else if (of_device_is_compatible(np, "samsung,exynos5260-tmu"))
> +		return SOC_ARCH_EXYNOS5260;
> +	else if (of_device_is_compatible(np, "samsung,exynos5420-tmu"))
> +		return SOC_ARCH_EXYNOS5420;
> +	else if (of_device_is_compatible(np,
> +					 "samsung,exynos5420-tmu-ext-triminfo"))
> +		return SOC_ARCH_EXYNOS5420_TRIMINFO;
> +	else if (of_device_is_compatible(np, "samsung,exynos5440-tmu"))
> +		return SOC_ARCH_EXYNOS5440;
> +
> +	return -EINVAL;
> +}
>  
> -	match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
> -	if (!match)
> -		return NULL;
> -	data_table = (struct exynos_tmu_init_data *) match->data;
> -	if (!data_table || id >= data_table->tmu_count)
> -		return NULL;
> -	tmu_data = data_table->tmu_data;
> -	return (struct exynos_tmu_platform_data *) (tmu_data + id);
> +static int exynos_of_sensor_conf(struct device_node *np,
> +				 struct exynos_tmu_platform_data *pdata)
> +{
> +	u32 value;
> +	int ret;
> +
> +	of_node_get(np);
> +
> +	ret = of_property_read_u32(np, "samsung,tmu_gain", &value);
> +	pdata->gain = (u8) value;
> +	of_property_read_u32(np, "samsung,tmu_reference_voltage", &value);
> +	pdata->reference_voltage = (u8) value;
> +	of_property_read_u32(np, "samsung,tmu_noise_cancel_mode", &value);
> +	pdata->noise_cancel_mode = (u8) value;
> +
> +	of_property_read_u32(np, "samsung,tmu_efuse_value",
> +			     &pdata->efuse_value);
> +	of_property_read_u32(np, "samsung,tmu_min_efuse_value",
> +			     &pdata->min_efuse_value);
> +	of_property_read_u32(np, "samsung,tmu_max_efuse_value",
> +			     &pdata->max_efuse_value);
> +
> +	of_property_read_u32(np, "samsung,tmu_first_point_trim", &value);
> +	pdata->first_point_trim = (u8) value;
> +	of_property_read_u32(np, "samsung,tmu_second_point_trim", &value);
> +	pdata->second_point_trim = (u8) value;
> +	of_property_read_u32(np, "samsung,tmu_default_temp_offset", &value);
> +	pdata->default_temp_offset = (u8) value;
> +
> +	of_property_read_u32(np, "samsung,tmu_cal_type", &pdata->cal_type);
> +	of_property_read_u32(np, "samsung,tmu_cal_mode", &pdata->cal_mode);
> +
> +	of_node_put(np);
> +	return 0;
>  }
>  
>  static int exynos_map_dt_data(struct platform_device *pdev)
> @@ -771,14 +892,15 @@ static int exynos_map_dt_data(struct platform_device *pdev)
>  		return -EADDRNOTAVAIL;
>  	}
>  
> -	pdata = exynos_get_driver_data(pdev, data->id);
> -	if (!pdata) {
> -		dev_err(&pdev->dev, "No platform init data supplied.\n");
> -		return -ENODEV;
> -	}
> +	pdata = devm_kzalloc(&pdev->dev,
> +			     sizeof(struct exynos_tmu_platform_data),
> +			     GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
>  
> +	exynos_of_sensor_conf(pdev->dev.of_node, pdata);
>  	data->pdata = pdata;
> -	data->soc = pdata->type;
> +	data->soc = exynos_of_get_soc_type(pdev->dev.of_node);
>  
>  	switch (data->soc) {
>  	case SOC_ARCH_EXYNOS4210:
> @@ -834,12 +956,16 @@ static int exynos_map_dt_data(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static struct thermal_zone_of_device_ops exynos_sensor_ops = {
> +	.get_temp = exynos_get_temp,
> +	.set_emul_temp = exynos_tmu_set_emulation,
> +};
> +
>  static int exynos_tmu_probe(struct platform_device *pdev)
>  {
> -	struct exynos_tmu_data *data;
>  	struct exynos_tmu_platform_data *pdata;
> -	struct thermal_sensor_conf *sensor_conf;
> -	int ret, i;
> +	struct exynos_tmu_data *data;
> +	int ret;
>  
>  	data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
>  					GFP_KERNEL);
> @@ -849,9 +975,15 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>  	platform_set_drvdata(pdev, data);
>  	mutex_init(&data->lock);
>  
> +	data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
> +						    &exynos_sensor_ops);
> +	if (IS_ERR(data->tzd)) {
> +		pr_err("thermal: tz: %p ERROR\n", data->tzd);
> +		return PTR_ERR(data->tzd);
> +	}
>  	ret = exynos_map_dt_data(pdev);
>  	if (ret)
> -		return ret;
> +		goto err_sensor;
>  
>  	pdata = data->pdata;
>  
> @@ -860,20 +992,22 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>  	data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
>  	if (IS_ERR(data->clk)) {
>  		dev_err(&pdev->dev, "Failed to get clock\n");
> -		return  PTR_ERR(data->clk);
> +		ret = PTR_ERR(data->clk);
> +		goto err_sensor;
>  	}
>  
>  	data->clk_sec = devm_clk_get(&pdev->dev, "tmu_triminfo_apbif");
>  	if (IS_ERR(data->clk_sec)) {
>  		if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) {
>  			dev_err(&pdev->dev, "Failed to get triminfo clock\n");
> -			return PTR_ERR(data->clk_sec);
> +			ret = PTR_ERR(data->clk_sec);
> +			goto err_sensor;
>  		}
>  	} else {
>  		ret = clk_prepare(data->clk_sec);
>  		if (ret) {
>  			dev_err(&pdev->dev, "Failed to get clock\n");
> -			return ret;
> +			goto err_sensor;
>  		}
>  	}
>  
> @@ -889,45 +1023,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>  		goto err_clk;
>  	}
>  
> -	exynos_tmu_control(pdev, true);
> -
> -	/* Allocate a structure to register with the exynos core thermal */
> -	sensor_conf = devm_kzalloc(&pdev->dev,
> -				sizeof(struct thermal_sensor_conf), GFP_KERNEL);
> -	if (!sensor_conf) {
> -		ret = -ENOMEM;
> -		goto err_clk;
> -	}
> -	sprintf(sensor_conf->name, "therm_zone%d", data->id);
> -	sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read;
> -	sensor_conf->write_emul_temp =
> -		(int (*)(void *, unsigned long))exynos_tmu_set_emulation;
> -	sensor_conf->driver_data = data;
> -	sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] +
> -			pdata->trigger_enable[1] + pdata->trigger_enable[2]+
> -			pdata->trigger_enable[3];
> -
> -	for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
> -		sensor_conf->trip_data.trip_val[i] =
> -			pdata->threshold + pdata->trigger_levels[i];
> -		sensor_conf->trip_data.trip_type[i] =
> -					pdata->trigger_type[i];
> -	}
> -
> -	sensor_conf->trip_data.trigger_falling = pdata->threshold_falling;
> -
> -	sensor_conf->dev = &pdev->dev;
> -	/* Register the sensor with thermal management interface */
> -	ret = exynos_register_thermal(sensor_conf);
> -	if (ret) {
> -		if (ret != -EPROBE_DEFER)
> -			dev_err(&pdev->dev,
> -				"Failed to register thermal interface: %d\n",
> -				ret);
> -		goto err_clk;
> -	}
> -	data->reg_conf = sensor_conf;
> -
>  	ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
>  		IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
>  	if (ret) {
> @@ -935,21 +1030,31 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>  		goto err_clk;
>  	}
>  
> +	ret = exynos_tmu_initialize(pdev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to initialize TMU\n");
> +		goto err_clk;
> +	}
> +	exynos_tmu_control(pdev, true);
>  	return 0;
> +
>  err_clk:
>  	clk_unprepare(data->clk);
>  err_clk_sec:
>  	if (!IS_ERR(data->clk_sec))
>  		clk_unprepare(data->clk_sec);
> +err_sensor:
> +	thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
> +
>  	return ret;
>  }
>  
>  static int exynos_tmu_remove(struct platform_device *pdev)
>  {
>  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> +	struct thermal_zone_device *tzd = data->tzd;
>  
> -	exynos_unregister_thermal(data->reg_conf);
> -
> +	thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
>  	exynos_tmu_control(pdev, false);
>  
>  	clk_unprepare(data->clk);
> diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
> index 627dec9..d876d4c 100644
> --- a/drivers/thermal/samsung/exynos_tmu.h
> +++ b/drivers/thermal/samsung/exynos_tmu.h
> @@ -23,8 +23,7 @@
>  #ifndef _EXYNOS_TMU_H
>  #define _EXYNOS_TMU_H
>  #include <linux/cpu_cooling.h>
> -
> -#include "exynos_thermal_common.h"
> +#include <dt-bindings/thermal/thermal_exynos.h>
>  
>  enum soc_type {
>  	SOC_ARCH_EXYNOS3250 = 1,
> @@ -36,38 +35,9 @@ enum soc_type {
>  	SOC_ARCH_EXYNOS5420_TRIMINFO,
>  	SOC_ARCH_EXYNOS5440,
>  };
> -#include <dt-bindings/thermal/thermal_exynos.h>
>  
>  /**
>   * struct exynos_tmu_platform_data
> - * @threshold: basic temperature for generating interrupt
> - *	       25 <= threshold <= 125 [unit: degree Celsius]
> - * @threshold_falling: differntial value for setting threshold
> - *		       of temperature falling interrupt.
> - * @trigger_levels: array for each interrupt levels
> - *	[unit: degree Celsius]
> - *	0: temperature for trigger_level0 interrupt
> - *	   condition for trigger_level0 interrupt:
> - *		current temperature > threshold + trigger_levels[0]
> - *	1: temperature for trigger_level1 interrupt
> - *	   condition for trigger_level1 interrupt:
> - *		current temperature > threshold + trigger_levels[1]
> - *	2: temperature for trigger_level2 interrupt
> - *	   condition for trigger_level2 interrupt:
> - *		current temperature > threshold + trigger_levels[2]
> - *	3: temperature for trigger_level3 interrupt
> - *	   condition for trigger_level3 interrupt:
> - *		current temperature > threshold + trigger_levels[3]
> - * @trigger_type: defines the type of trigger. Possible values are,
> - *	THROTTLE_ACTIVE trigger type
> - *	THROTTLE_PASSIVE trigger type
> - *	SW_TRIP trigger type
> - *	HW_TRIP
> - * @trigger_enable[]: array to denote which trigger levels are enabled.
> - *	1 = enable trigger_level[] interrupt,
> - *	0 = disable trigger_level[] interrupt
> - * @max_trigger_level: max trigger level supported by the TMU
> - * @non_hw_trigger_levels: number of defined non-hardware trigger levels
>   * @gain: gain of amplifier in the positive-TC generator block
>   *	0 < gain <= 15
>   * @reference_voltage: reference voltage of amplifier
> @@ -79,21 +49,12 @@ enum soc_type {
>   * @efuse_value: platform defined fuse value
>   * @min_efuse_value: minimum valid trimming data
>   * @max_efuse_value: maximum valid trimming data
> - * @first_point_trim: temp value of the first point trimming
> - * @second_point_trim: temp value of the second point trimming
>   * @default_temp_offset: default temperature offset in case of no trimming
>   * @cal_type: calibration type for temperature
>   *
>   * This structure is required for configuration of exynos_tmu driver.
>   */
>  struct exynos_tmu_platform_data {
> -	u8 threshold;
> -	u8 threshold_falling;
> -	u8 trigger_levels[MAX_TRIP_COUNT];
> -	enum trigger_type trigger_type[MAX_TRIP_COUNT];
> -	bool trigger_enable[MAX_TRIP_COUNT];
> -	u8 max_trigger_level;
> -	u8 non_hw_trigger_levels;
>  	u8 gain;
>  	u8 reference_voltage;
>  	u8 noise_cancel_mode;
> @@ -110,18 +71,6 @@ struct exynos_tmu_platform_data {
>  	u32 cal_mode;
>  };
>  
> -/**
> - * struct exynos_tmu_init_data
> - * @tmu_count: number of TMU instances.
> - * @tmu_data: platform data of all TMU instances.
> - * This structure is required to store data for multi-instance exynos tmu
> - * driver.
> - */
> -struct exynos_tmu_init_data {
> -	int tmu_count;
> -	struct exynos_tmu_platform_data tmu_data[];
> -};
> -
>  extern struct exynos_tmu_init_data const exynos3250_default_tmu_data;
>  extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
>  extern struct exynos_tmu_init_data const exynos4412_default_tmu_data;
> -- 
> 2.0.0.rc2
>
Lukasz Majewski Jan. 15, 2015, 3:17 p.m. UTC | #2
Hi Eduardo,

> On Wed, Jan 14, 2015 at 02:41:12PM +0100, Lukasz Majewski wrote:
> > This patch brings support for providing configuration via device
> > tree. Previously this data has been hardcoded in the
> > exynos_tmu_data.c file. Such approach was not scalable and very
> > often required copying the whole data.
> > 
> > Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> > ---
> > Changes for v2:
> > - Adjust exynos_tmu.c code to the newest ti-soc-thermal repository
> > - Usage of of-thermal.c exported trip points table
> > Changes for v3:
> > - Adding exynos_of_get_soc_type() method to set SOC type from
> > device's compatible string
> > - "samsung,tmu_" prefix for TMU specific properties has been added
> > 
> > ---
> >  drivers/thermal/samsung/Makefile     |   2 -
> >  drivers/thermal/samsung/exynos_tmu.c | 345
> > +++++++++++++++++++++++------------
> > drivers/thermal/samsung/exynos_tmu.h |  53 +----- 3 files changed,
> > 226 insertions(+), 174 deletions(-)
> > 
> > diff --git a/drivers/thermal/samsung/Makefile
> > b/drivers/thermal/samsung/Makefile index c09d830..1e47d0d 100644
> > --- a/drivers/thermal/samsung/Makefile
> > +++ b/drivers/thermal/samsung/Makefile
> > @@ -3,5 +3,3 @@
> >  #
> >  obj-$(CONFIG_EXYNOS_THERMAL)			+=
> > exynos_thermal.o exynos_thermal-y				:=
> > exynos_tmu.o -exynos_thermal-y				+=
> > exynos_tmu_data.o
> 
> Can this makefile change be part of the patch that removes
> exynos_tmu_data.c?
> 
> > -exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE)	+=
> > exynos_thermal_common.o
> 
> Can this makefile change be part of the patch that removes
> exynos_thermal_common.c?

Unfortunately, this code cannot be moved to the next patch, in which I
remove the files, since this causes build break of the series.

The code structure as is, provides working, bisectable thermal
solution - thermal and cpu_cooling functionality is preserved across
all commits in the series.

> 
> > diff --git a/drivers/thermal/samsung/exynos_tmu.c
> > b/drivers/thermal/samsung/exynos_tmu.c index ae30f6a..633a9e2 100644
> > --- a/drivers/thermal/samsung/exynos_tmu.c
> > +++ b/drivers/thermal/samsung/exynos_tmu.c
> > @@ -1,6 +1,10 @@
> >  /*
> >   * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit)
> >   *
> > + *  Copyright (C) 2014 Samsung Electronics
> > + *  Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> > + *  Lukasz Majewski <l.majewski@samsung.com>
> > + *
> >   *  Copyright (C) 2011 Samsung Electronics
> >   *  Donggeun Kim <dg77.kim@samsung.com>
> >   *  Amit Daniel Kachhap <amit.kachhap@linaro.org>
> > @@ -31,8 +35,8 @@
> >  #include <linux/platform_device.h>
> >  #include <linux/regulator/consumer.h>
> >  
> > -#include "exynos_thermal_common.h"
> >  #include "exynos_tmu.h"
> > +#include "../thermal_core.h"
> >  
> >  /* Exynos generic registers */
> >  #define EXYNOS_TMU_REG_TRIMINFO		0x0
> > @@ -115,6 +119,7 @@
> >  #define EXYNOS5440_TMU_TH_RISE4_SHIFT		24
> >  #define EXYNOS5440_EFUSE_SWAP_OFFSET		8
> >  
> > +#define MCELSIUS	1000
> >  /**
> >   * struct exynos_tmu_data : A structure to hold the private data
> > of the TMU driver
> > @@ -150,7 +155,8 @@ struct exynos_tmu_data {
> >  	struct clk *clk, *clk_sec;
> >  	u8 temp_error1, temp_error2;
> >  	struct regulator *regulator;
> > -	struct thermal_sensor_conf *reg_conf;
> > +	struct thermal_zone_device *tzd;
> > +
> >  	int (*tmu_initialize)(struct platform_device *pdev);
> >  	void (*tmu_control)(struct platform_device *pdev, bool on);
> >  	int (*tmu_read)(struct exynos_tmu_data *data);
> > @@ -159,6 +165,33 @@ struct exynos_tmu_data {
> >  	void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
> >  };
> >  
> > +static void exynos_report_trigger(struct exynos_tmu_data *p)
> > +{
> > +	char data[10], *envp[] = { data, NULL };
> > +	struct thermal_zone_device *tz = p->tzd;
> > +	unsigned long temp;
> > +	unsigned int i;
> > +
> > +	if (!p) {
> > +		pr_err("Wrong temperature configuration data\n");
> > +		return;
> > +	}
> > +
> > +	thermal_zone_device_update(tz);
> > +
> > +	mutex_lock(&tz->lock);
> > +	/* Find the level for which trip happened */
> > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > +		tz->ops->get_trip_temp(tz, i, &temp);
> > +		if (tz->last_temperature < temp)
> > +			break;
> > +	}
> > +
> > +	snprintf(data, sizeof(data), "%u", i);
> > +	kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, envp);
> > +	mutex_unlock(&tz->lock);
> > +}
> > +
> >  /*
> >   * TMU treats temperature as a mapped temperature code.
> >   * The temperature is converted differently depending on the
> > calibration type. @@ -234,14 +267,25 @@ static void
> > sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info) 
> >  static u32 get_th_reg(struct exynos_tmu_data *data, u32 threshold,
> > bool falling) {
> > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > +	struct thermal_zone_device *tz = data->tzd;
> > +	const struct thermal_trip * const trips =
> > +		of_thermal_get_trip_points(tz);
> > +	unsigned long temp;
> >  	int i;
> >  
> > -	for (i = 0; i < pdata->non_hw_trigger_levels; i++) {
> > -		u8 temp = pdata->trigger_levels[i];
> > +	if (!trips) {
> > +		pr_err("%s: Cannot get trip points from
> > of-thermal.c!\n",
> > +		       __func__);
> > +		return 0;
> > +	}
> > +
> > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > +		if (trips[i].type == THERMAL_TRIP_CRITICAL)
> > +			continue;
> >  
> > +		temp = trips[i].temperature / MCELSIUS;
> >  		if (falling)
> > -			temp -= pdata->threshold_falling;
> > +			temp -= (trips[i].hysteresis / MCELSIUS);
> >  		else
> >  			threshold &= ~(0xff << 8 * i);
> >  
> > @@ -305,9 +349,19 @@ static void exynos_tmu_control(struct
> > platform_device *pdev, bool on) static int
> > exynos4210_tmu_initialize(struct platform_device *pdev) {
> >  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > -	unsigned int status;
> > +	struct thermal_zone_device *tz = data->tzd;
> > +	const struct thermal_trip * const trips =
> > +		of_thermal_get_trip_points(tz);
> >  	int ret = 0, threshold_code, i;
> > +	unsigned long reference, temp;
> > +	unsigned int status;
> > +
> > +	if (!trips) {
> > +		pr_err("%s: Cannot get trip points from
> > of-thermal.c!\n",
> > +		       __func__);
> > +		ret = -ENODEV;
> > +		goto out;
> > +	}
> >  
> >  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> >  	if (!status) {
> > @@ -318,12 +372,19 @@ static int exynos4210_tmu_initialize(struct
> > platform_device *pdev) sanitize_temp_error(data, readl(data->base +
> > EXYNOS_TMU_REG_TRIMINFO)); 
> >  	/* Write temperature code for threshold */
> > -	threshold_code = temp_to_code(data, pdata->threshold);
> > +	reference = trips[0].temperature / MCELSIUS;
> > +	threshold_code = temp_to_code(data, reference);
> > +	if (threshold_code < 0) {
> > +		ret = threshold_code;
> > +		goto out;
> > +	}
> >  	writeb(threshold_code, data->base +
> > EXYNOS4210_TMU_REG_THRESHOLD_TEMP); 
> > -	for (i = 0; i < pdata->non_hw_trigger_levels; i++)
> > -		writeb(pdata->trigger_levels[i], data->base +
> > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > +		temp = trips[i].temperature / MCELSIUS;
> > +		writeb(temp - reference, data->base +
> >  		       EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
> > +	}
> >  
> >  	data->tmu_clear_irqs(data);
> >  out:
> > @@ -333,9 +394,11 @@ out:
> >  static int exynos4412_tmu_initialize(struct platform_device *pdev)
> >  {
> >  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > +	const struct thermal_trip * const trips =
> > +		of_thermal_get_trip_points(data->tzd);
> >  	unsigned int status, trim_info, con, ctrl,
> > rising_threshold; int ret = 0, threshold_code, i;
> > +	unsigned long crit_temp = 0;
> >  
> >  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> >  	if (!status) {
> > @@ -373,17 +436,29 @@ static int exynos4412_tmu_initialize(struct
> > platform_device *pdev) data->tmu_clear_irqs(data);
> >  
> >  	/* if last threshold limit is also present */
> > -	i = pdata->max_trigger_level - 1;
> > -	if (pdata->trigger_levels[i] && pdata->trigger_type[i] ==
> > HW_TRIP) {
> > -		threshold_code = temp_to_code(data,
> > pdata->trigger_levels[i]);
> > -		/* 1-4 level to be assigned in th0 reg */
> > -		rising_threshold &= ~(0xff << 8 * i);
> > -		rising_threshold |= threshold_code << 8 * i;
> > -		writel(rising_threshold, data->base +
> > EXYNOS_THD_TEMP_RISE);
> > -		con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
> > -		con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > -		writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> > +	for (i = 0; i < of_thermal_get_ntrips(data->tzd); i++) {
> > +		if (trips[i].type == THERMAL_TRIP_CRITICAL) {
> > +			crit_temp = trips[i].temperature;
> > +			break;
> > +		}
> >  	}
> > +
> > +	if (i == of_thermal_get_ntrips(data->tzd)) {
> > +		pr_err("%s: No CRITICAL trip point defined at
> > of-thermal.c!\n",
> > +		       __func__);
> > +		ret = -EINVAL;
> > +		goto out;
> > +	}
> > +
> > +	threshold_code = temp_to_code(data, crit_temp / MCELSIUS);
> > +	/* 1-4 level to be assigned in th0 reg */
> > +	rising_threshold &= ~(0xff << 8 * i);
> > +	rising_threshold |= threshold_code << 8 * i;
> > +	writel(rising_threshold, data->base +
> > EXYNOS_THD_TEMP_RISE);
> > +	con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
> > +	con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > +	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> > +
> >  out:
> >  	return ret;
> >  }
> > @@ -391,9 +466,9 @@ out:
> >  static int exynos5440_tmu_initialize(struct platform_device *pdev)
> >  {
> >  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> >  	unsigned int trim_info = 0, con, rising_threshold;
> > -	int ret = 0, threshold_code, i;
> > +	int ret = 0, threshold_code;
> > +	unsigned long crit_temp = 0;
> >  
> >  	/*
> >  	 * For exynos5440 soc triminfo value is swapped between
> > TMU0 and @@ -422,9 +497,8 @@ static int
> > exynos5440_tmu_initialize(struct platform_device *pdev)
> > data->tmu_clear_irqs(data); 
> >  	/* if last threshold limit is also present */
> > -	i = pdata->max_trigger_level - 1;
> > -	if (pdata->trigger_levels[i] && pdata->trigger_type[i] ==
> > HW_TRIP) {
> > -		threshold_code = temp_to_code(data,
> > pdata->trigger_levels[i]);
> > +	if (!data->tzd->ops->get_crit_temp(data->tzd, &crit_temp))
> > {
> > +		threshold_code = temp_to_code(data, crit_temp /
> > MCELSIUS); /* 5th level to be assigned in th2 reg */
> >  		rising_threshold =
> >  			threshold_code <<
> > EXYNOS5440_TMU_TH_RISE4_SHIFT; @@ -442,7 +516,7 @@ static int
> > exynos5440_tmu_initialize(struct platform_device *pdev) static void
> > exynos4210_tmu_control(struct platform_device *pdev, bool on) {
> >  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > +	struct thermal_zone_device *tz = data->tzd;
> >  	unsigned int con, interrupt_en;
> >  
> >  	con = get_con_reg(data, readl(data->base +
> > EXYNOS_TMU_REG_CONTROL)); @@ -450,10 +524,15 @@ static void
> > exynos4210_tmu_control(struct platform_device *pdev, bool on) if
> > (on) { con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> >  		interrupt_en =
> > -			pdata->trigger_enable[3] <<
> > EXYNOS_TMU_INTEN_RISE3_SHIFT |
> > -			pdata->trigger_enable[2] <<
> > EXYNOS_TMU_INTEN_RISE2_SHIFT |
> > -			pdata->trigger_enable[1] <<
> > EXYNOS_TMU_INTEN_RISE1_SHIFT |
> > -			pdata->trigger_enable[0] <<
> > EXYNOS_TMU_INTEN_RISE0_SHIFT;
> > +			(of_thermal_is_trip_valid(tz, 3)
> > +			 << EXYNOS_TMU_INTEN_RISE3_SHIFT) |
> > +			(of_thermal_is_trip_valid(tz, 2)
> > +			 << EXYNOS_TMU_INTEN_RISE2_SHIFT) |
> > +			(of_thermal_is_trip_valid(tz, 1)
> > +			 << EXYNOS_TMU_INTEN_RISE1_SHIFT) |
> > +			(of_thermal_is_trip_valid(tz, 0)
> > +			 << EXYNOS_TMU_INTEN_RISE0_SHIFT);
> > +
> >  		if (data->soc != SOC_ARCH_EXYNOS4210)
> >  			interrupt_en |=
> >  				interrupt_en <<
> > EXYNOS_TMU_INTEN_FALL0_SHIFT; @@ -468,7 +547,7 @@ static void
> > exynos4210_tmu_control(struct platform_device *pdev, bool on)
> > static void exynos5440_tmu_control(struct platform_device *pdev,
> > bool on) { struct exynos_tmu_data *data =
> > platform_get_drvdata(pdev);
> > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > +	struct thermal_zone_device *tz = data->tzd;
> >  	unsigned int con, interrupt_en;
> >  
> >  	con = get_con_reg(data, readl(data->base +
> > EXYNOS5440_TMU_S0_7_CTRL)); @@ -476,11 +555,16 @@ static void
> > exynos5440_tmu_control(struct platform_device *pdev, bool on) if
> > (on) { con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> >  		interrupt_en =
> > -			pdata->trigger_enable[3] <<
> > EXYNOS5440_TMU_INTEN_RISE3_SHIFT |
> > -			pdata->trigger_enable[2] <<
> > EXYNOS5440_TMU_INTEN_RISE2_SHIFT |
> > -			pdata->trigger_enable[1] <<
> > EXYNOS5440_TMU_INTEN_RISE1_SHIFT |
> > -			pdata->trigger_enable[0] <<
> > EXYNOS5440_TMU_INTEN_RISE0_SHIFT;
> > -		interrupt_en |= interrupt_en <<
> > EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
> > +			(of_thermal_is_trip_valid(tz, 3)
> > +			 << EXYNOS5440_TMU_INTEN_RISE3_SHIFT) |
> > +			(of_thermal_is_trip_valid(tz, 2)
> > +			 << EXYNOS5440_TMU_INTEN_RISE2_SHIFT) |
> > +			(of_thermal_is_trip_valid(tz, 1)
> > +			 << EXYNOS5440_TMU_INTEN_RISE1_SHIFT) |
> > +			(of_thermal_is_trip_valid(tz, 0)
> > +			 << EXYNOS5440_TMU_INTEN_RISE0_SHIFT);
> > +		interrupt_en |=
> > +			interrupt_en <<
> > EXYNOS5440_TMU_INTEN_FALL0_SHIFT; } else {
> >  		con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
> >  		interrupt_en = 0; /* Disable all interrupts */
> > @@ -489,19 +573,22 @@ static void exynos5440_tmu_control(struct
> > platform_device *pdev, bool on) writel(con, data->base +
> > EXYNOS5440_TMU_S0_7_CTRL); }
> >  
> > -static int exynos_tmu_read(struct exynos_tmu_data *data)
> > +int exynos_get_temp(void *p, long *temp)
> >  {
> > -	int ret;
> > +	struct exynos_tmu_data *data = p;
> > +
> > +	if (!data)
> > +		return -EINVAL;
> >  
> >  	mutex_lock(&data->lock);
> >  	clk_enable(data->clk);
> > -	ret = data->tmu_read(data);
> > -	if (ret >= 0)
> > -		ret = code_to_temp(data, ret);
> > +
> > +	*temp = code_to_temp(data, data->tmu_read(data)) *
> > MCELSIUS; +
> >  	clk_disable(data->clk);
> >  	mutex_unlock(&data->lock);
> >  
> > -	return ret;
> > +	return 0;
> >  }
> >  
> >  #ifdef CONFIG_THERMAL_EMULATION
> > @@ -613,7 +700,7 @@ static void exynos_tmu_work(struct work_struct
> > *work) if (!IS_ERR(data->clk_sec))
> >  		clk_disable(data->clk_sec);
> >  
> > -	exynos_report_trigger(data->reg_conf);
> > +	exynos_report_trigger(data);
> >  	mutex_lock(&data->lock);
> >  	clk_enable(data->clk);
> >  
> > @@ -673,55 +760,89 @@ static irqreturn_t exynos_tmu_irq(int irq,
> > void *id) static const struct of_device_id exynos_tmu_match[] = {
> >  	{
> >  		.compatible = "samsung,exynos3250-tmu",
> > -		.data = &exynos3250_default_tmu_data,
> >  	},
> >  	{
> >  		.compatible = "samsung,exynos4210-tmu",
> > -		.data = &exynos4210_default_tmu_data,
> >  	},
> >  	{
> >  		.compatible = "samsung,exynos4412-tmu",
> > -		.data = &exynos4412_default_tmu_data,
> >  	},
> >  	{
> >  		.compatible = "samsung,exynos5250-tmu",
> > -		.data = &exynos5250_default_tmu_data,
> >  	},
> >  	{
> >  		.compatible = "samsung,exynos5260-tmu",
> > -		.data = &exynos5260_default_tmu_data,
> >  	},
> >  	{
> >  		.compatible = "samsung,exynos5420-tmu",
> > -		.data = &exynos5420_default_tmu_data,
> >  	},
> >  	{
> >  		.compatible =
> > "samsung,exynos5420-tmu-ext-triminfo",
> > -		.data = &exynos5420_default_tmu_data,
> >  	},
> >  	{
> >  		.compatible = "samsung,exynos5440-tmu",
> > -		.data = &exynos5440_default_tmu_data,
> >  	},
> >  	{},
> >  };
> >  MODULE_DEVICE_TABLE(of, exynos_tmu_match);
> >  
> > -static inline struct  exynos_tmu_platform_data
> > *exynos_get_driver_data(
> > -			struct platform_device *pdev, int id)
> > +static int exynos_of_get_soc_type(struct device_node *np)
> >  {
> > -	struct  exynos_tmu_init_data *data_table;
> > -	struct exynos_tmu_platform_data *tmu_data;
> > -	const struct of_device_id *match;
> > +	if (of_device_is_compatible(np, "samsung,exynos3250-tmu"))
> > +		return SOC_ARCH_EXYNOS3250;
> > +	else if (of_device_is_compatible(np,
> > "samsung,exynos4210-tmu"))
> > +		return SOC_ARCH_EXYNOS4210;
> > +	else if (of_device_is_compatible(np,
> > "samsung,exynos4412-tmu"))
> > +		return SOC_ARCH_EXYNOS4412;
> > +	else if (of_device_is_compatible(np,
> > "samsung,exynos5250-tmu"))
> > +		return SOC_ARCH_EXYNOS5250;
> > +	else if (of_device_is_compatible(np,
> > "samsung,exynos5260-tmu"))
> > +		return SOC_ARCH_EXYNOS5260;
> > +	else if (of_device_is_compatible(np,
> > "samsung,exynos5420-tmu"))
> > +		return SOC_ARCH_EXYNOS5420;
> > +	else if (of_device_is_compatible(np,
> > +
> > "samsung,exynos5420-tmu-ext-triminfo"))
> > +		return SOC_ARCH_EXYNOS5420_TRIMINFO;
> > +	else if (of_device_is_compatible(np,
> > "samsung,exynos5440-tmu"))
> > +		return SOC_ARCH_EXYNOS5440;
> > +
> > +	return -EINVAL;
> > +}
> >  
> > -	match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
> > -	if (!match)
> > -		return NULL;
> > -	data_table = (struct exynos_tmu_init_data *) match->data;
> > -	if (!data_table || id >= data_table->tmu_count)
> > -		return NULL;
> > -	tmu_data = data_table->tmu_data;
> > -	return (struct exynos_tmu_platform_data *) (tmu_data + id);
> > +static int exynos_of_sensor_conf(struct device_node *np,
> > +				 struct exynos_tmu_platform_data
> > *pdata) +{
> > +	u32 value;
> > +	int ret;
> > +
> > +	of_node_get(np);
> > +
> > +	ret = of_property_read_u32(np, "samsung,tmu_gain", &value);
> > +	pdata->gain = (u8) value;
> > +	of_property_read_u32(np, "samsung,tmu_reference_voltage",
> > &value);
> > +	pdata->reference_voltage = (u8) value;
> > +	of_property_read_u32(np, "samsung,tmu_noise_cancel_mode",
> > &value);
> > +	pdata->noise_cancel_mode = (u8) value;
> > +
> > +	of_property_read_u32(np, "samsung,tmu_efuse_value",
> > +			     &pdata->efuse_value);
> > +	of_property_read_u32(np, "samsung,tmu_min_efuse_value",
> > +			     &pdata->min_efuse_value);
> > +	of_property_read_u32(np, "samsung,tmu_max_efuse_value",
> > +			     &pdata->max_efuse_value);
> > +
> > +	of_property_read_u32(np, "samsung,tmu_first_point_trim",
> > &value);
> > +	pdata->first_point_trim = (u8) value;
> > +	of_property_read_u32(np, "samsung,tmu_second_point_trim",
> > &value);
> > +	pdata->second_point_trim = (u8) value;
> > +	of_property_read_u32(np,
> > "samsung,tmu_default_temp_offset", &value);
> > +	pdata->default_temp_offset = (u8) value;
> > +
> > +	of_property_read_u32(np, "samsung,tmu_cal_type",
> > &pdata->cal_type);
> > +	of_property_read_u32(np, "samsung,tmu_cal_mode",
> > &pdata->cal_mode); +
> > +	of_node_put(np);
> > +	return 0;
> >  }
> >  
> >  static int exynos_map_dt_data(struct platform_device *pdev)
> > @@ -771,14 +892,15 @@ static int exynos_map_dt_data(struct
> > platform_device *pdev) return -EADDRNOTAVAIL;
> >  	}
> >  
> > -	pdata = exynos_get_driver_data(pdev, data->id);
> > -	if (!pdata) {
> > -		dev_err(&pdev->dev, "No platform init data
> > supplied.\n");
> > -		return -ENODEV;
> > -	}
> > +	pdata = devm_kzalloc(&pdev->dev,
> > +			     sizeof(struct
> > exynos_tmu_platform_data),
> > +			     GFP_KERNEL);
> > +	if (!pdata)
> > +		return -ENOMEM;
> >  
> > +	exynos_of_sensor_conf(pdev->dev.of_node, pdata);
> >  	data->pdata = pdata;
> > -	data->soc = pdata->type;
> > +	data->soc = exynos_of_get_soc_type(pdev->dev.of_node);
> >  
> >  	switch (data->soc) {
> >  	case SOC_ARCH_EXYNOS4210:
> > @@ -834,12 +956,16 @@ static int exynos_map_dt_data(struct
> > platform_device *pdev) return 0;
> >  }
> >  
> > +static struct thermal_zone_of_device_ops exynos_sensor_ops = {
> > +	.get_temp = exynos_get_temp,
> > +	.set_emul_temp = exynos_tmu_set_emulation,
> > +};
> > +
> >  static int exynos_tmu_probe(struct platform_device *pdev)
> >  {
> > -	struct exynos_tmu_data *data;
> >  	struct exynos_tmu_platform_data *pdata;
> > -	struct thermal_sensor_conf *sensor_conf;
> > -	int ret, i;
> > +	struct exynos_tmu_data *data;
> > +	int ret;
> >  
> >  	data = devm_kzalloc(&pdev->dev, sizeof(struct
> > exynos_tmu_data), GFP_KERNEL);
> > @@ -849,9 +975,15 @@ static int exynos_tmu_probe(struct
> > platform_device *pdev) platform_set_drvdata(pdev, data);
> >  	mutex_init(&data->lock);
> >  
> > +	data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0,
> > data,
> > +
> > &exynos_sensor_ops);
> > +	if (IS_ERR(data->tzd)) {
> > +		pr_err("thermal: tz: %p ERROR\n", data->tzd);
> > +		return PTR_ERR(data->tzd);
> > +	}
> >  	ret = exynos_map_dt_data(pdev);
> >  	if (ret)
> > -		return ret;
> > +		goto err_sensor;
> >  
> >  	pdata = data->pdata;
> >  
> > @@ -860,20 +992,22 @@ static int exynos_tmu_probe(struct
> > platform_device *pdev) data->clk = devm_clk_get(&pdev->dev,
> > "tmu_apbif"); if (IS_ERR(data->clk)) {
> >  		dev_err(&pdev->dev, "Failed to get clock\n");
> > -		return  PTR_ERR(data->clk);
> > +		ret = PTR_ERR(data->clk);
> > +		goto err_sensor;
> >  	}
> >  
> >  	data->clk_sec = devm_clk_get(&pdev->dev,
> > "tmu_triminfo_apbif"); if (IS_ERR(data->clk_sec)) {
> >  		if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) {
> >  			dev_err(&pdev->dev, "Failed to get
> > triminfo clock\n");
> > -			return PTR_ERR(data->clk_sec);
> > +			ret = PTR_ERR(data->clk_sec);
> > +			goto err_sensor;
> >  		}
> >  	} else {
> >  		ret = clk_prepare(data->clk_sec);
> >  		if (ret) {
> >  			dev_err(&pdev->dev, "Failed to get
> > clock\n");
> > -			return ret;
> > +			goto err_sensor;
> >  		}
> >  	}
> >  
> > @@ -889,45 +1023,6 @@ static int exynos_tmu_probe(struct
> > platform_device *pdev) goto err_clk;
> >  	}
> >  
> > -	exynos_tmu_control(pdev, true);
> > -
> > -	/* Allocate a structure to register with the exynos core
> > thermal */
> > -	sensor_conf = devm_kzalloc(&pdev->dev,
> > -				sizeof(struct
> > thermal_sensor_conf), GFP_KERNEL);
> > -	if (!sensor_conf) {
> > -		ret = -ENOMEM;
> > -		goto err_clk;
> > -	}
> > -	sprintf(sensor_conf->name, "therm_zone%d", data->id);
> > -	sensor_conf->read_temperature = (int (*)(void
> > *))exynos_tmu_read;
> > -	sensor_conf->write_emul_temp =
> > -		(int (*)(void *, unsigned
> > long))exynos_tmu_set_emulation;
> > -	sensor_conf->driver_data = data;
> > -	sensor_conf->trip_data.trip_count =
> > pdata->trigger_enable[0] +
> > -			pdata->trigger_enable[1] +
> > pdata->trigger_enable[2]+
> > -			pdata->trigger_enable[3];
> > -
> > -	for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
> > -		sensor_conf->trip_data.trip_val[i] =
> > -			pdata->threshold +
> > pdata->trigger_levels[i];
> > -		sensor_conf->trip_data.trip_type[i] =
> > -					pdata->trigger_type[i];
> > -	}
> > -
> > -	sensor_conf->trip_data.trigger_falling =
> > pdata->threshold_falling; -
> > -	sensor_conf->dev = &pdev->dev;
> > -	/* Register the sensor with thermal management interface */
> > -	ret = exynos_register_thermal(sensor_conf);
> > -	if (ret) {
> > -		if (ret != -EPROBE_DEFER)
> > -			dev_err(&pdev->dev,
> > -				"Failed to register thermal
> > interface: %d\n",
> > -				ret);
> > -		goto err_clk;
> > -	}
> > -	data->reg_conf = sensor_conf;
> > -
> >  	ret = devm_request_irq(&pdev->dev, data->irq,
> > exynos_tmu_irq, IRQF_TRIGGER_RISING | IRQF_SHARED,
> > dev_name(&pdev->dev), data); if (ret) {
> > @@ -935,21 +1030,31 @@ static int exynos_tmu_probe(struct
> > platform_device *pdev) goto err_clk;
> >  	}
> >  
> > +	ret = exynos_tmu_initialize(pdev);
> > +	if (ret) {
> > +		dev_err(&pdev->dev, "Failed to initialize TMU\n");
> > +		goto err_clk;
> > +	}
> > +	exynos_tmu_control(pdev, true);
> >  	return 0;
> > +
> >  err_clk:
> >  	clk_unprepare(data->clk);
> >  err_clk_sec:
> >  	if (!IS_ERR(data->clk_sec))
> >  		clk_unprepare(data->clk_sec);
> > +err_sensor:
> > +	thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
> > +
> >  	return ret;
> >  }
> >  
> >  static int exynos_tmu_remove(struct platform_device *pdev)
> >  {
> >  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > +	struct thermal_zone_device *tzd = data->tzd;
> >  
> > -	exynos_unregister_thermal(data->reg_conf);
> > -
> > +	thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
> >  	exynos_tmu_control(pdev, false);
> >  
> >  	clk_unprepare(data->clk);
> > diff --git a/drivers/thermal/samsung/exynos_tmu.h
> > b/drivers/thermal/samsung/exynos_tmu.h index 627dec9..d876d4c 100644
> > --- a/drivers/thermal/samsung/exynos_tmu.h
> > +++ b/drivers/thermal/samsung/exynos_tmu.h
> > @@ -23,8 +23,7 @@
> >  #ifndef _EXYNOS_TMU_H
> >  #define _EXYNOS_TMU_H
> >  #include <linux/cpu_cooling.h>
> > -
> > -#include "exynos_thermal_common.h"
> > +#include <dt-bindings/thermal/thermal_exynos.h>
> >  
> >  enum soc_type {
> >  	SOC_ARCH_EXYNOS3250 = 1,
> > @@ -36,38 +35,9 @@ enum soc_type {
> >  	SOC_ARCH_EXYNOS5420_TRIMINFO,
> >  	SOC_ARCH_EXYNOS5440,
> >  };
> > -#include <dt-bindings/thermal/thermal_exynos.h>
> >  
> >  /**
> >   * struct exynos_tmu_platform_data
> > - * @threshold: basic temperature for generating interrupt
> > - *	       25 <= threshold <= 125 [unit: degree Celsius]
> > - * @threshold_falling: differntial value for setting threshold
> > - *		       of temperature falling interrupt.
> > - * @trigger_levels: array for each interrupt levels
> > - *	[unit: degree Celsius]
> > - *	0: temperature for trigger_level0 interrupt
> > - *	   condition for trigger_level0 interrupt:
> > - *		current temperature > threshold +
> > trigger_levels[0]
> > - *	1: temperature for trigger_level1 interrupt
> > - *	   condition for trigger_level1 interrupt:
> > - *		current temperature > threshold +
> > trigger_levels[1]
> > - *	2: temperature for trigger_level2 interrupt
> > - *	   condition for trigger_level2 interrupt:
> > - *		current temperature > threshold +
> > trigger_levels[2]
> > - *	3: temperature for trigger_level3 interrupt
> > - *	   condition for trigger_level3 interrupt:
> > - *		current temperature > threshold +
> > trigger_levels[3]
> > - * @trigger_type: defines the type of trigger. Possible values are,
> > - *	THROTTLE_ACTIVE trigger type
> > - *	THROTTLE_PASSIVE trigger type
> > - *	SW_TRIP trigger type
> > - *	HW_TRIP
> > - * @trigger_enable[]: array to denote which trigger levels are
> > enabled.
> > - *	1 = enable trigger_level[] interrupt,
> > - *	0 = disable trigger_level[] interrupt
> > - * @max_trigger_level: max trigger level supported by the TMU
> > - * @non_hw_trigger_levels: number of defined non-hardware trigger
> > levels
> >   * @gain: gain of amplifier in the positive-TC generator block
> >   *	0 < gain <= 15
> >   * @reference_voltage: reference voltage of amplifier
> > @@ -79,21 +49,12 @@ enum soc_type {
> >   * @efuse_value: platform defined fuse value
> >   * @min_efuse_value: minimum valid trimming data
> >   * @max_efuse_value: maximum valid trimming data
> > - * @first_point_trim: temp value of the first point trimming
> > - * @second_point_trim: temp value of the second point trimming
> >   * @default_temp_offset: default temperature offset in case of no
> > trimming
> >   * @cal_type: calibration type for temperature
> >   *
> >   * This structure is required for configuration of exynos_tmu
> > driver. */
> >  struct exynos_tmu_platform_data {
> > -	u8 threshold;
> > -	u8 threshold_falling;
> > -	u8 trigger_levels[MAX_TRIP_COUNT];
> > -	enum trigger_type trigger_type[MAX_TRIP_COUNT];
> > -	bool trigger_enable[MAX_TRIP_COUNT];
> > -	u8 max_trigger_level;
> > -	u8 non_hw_trigger_levels;
> >  	u8 gain;
> >  	u8 reference_voltage;
> >  	u8 noise_cancel_mode;
> > @@ -110,18 +71,6 @@ struct exynos_tmu_platform_data {
> >  	u32 cal_mode;
> >  };
> >  
> > -/**
> > - * struct exynos_tmu_init_data
> > - * @tmu_count: number of TMU instances.
> > - * @tmu_data: platform data of all TMU instances.
> > - * This structure is required to store data for multi-instance
> > exynos tmu
> > - * driver.
> > - */
> > -struct exynos_tmu_init_data {
> > -	int tmu_count;
> > -	struct exynos_tmu_platform_data tmu_data[];
> > -};
> > -
> >  extern struct exynos_tmu_init_data const
> > exynos3250_default_tmu_data; extern struct exynos_tmu_init_data
> > const exynos4210_default_tmu_data; extern struct
> > exynos_tmu_init_data const exynos4412_default_tmu_data; -- 
> > 2.0.0.rc2
> >
Eduardo Valentin Jan. 21, 2015, 1:23 a.m. UTC | #3
On Thu, Jan 15, 2015 at 04:17:52PM +0100, Lukasz Majewski wrote:
> Hi Eduardo,
> 
> > On Wed, Jan 14, 2015 at 02:41:12PM +0100, Lukasz Majewski wrote:
> > > This patch brings support for providing configuration via device
> > > tree. Previously this data has been hardcoded in the
> > > exynos_tmu_data.c file. Such approach was not scalable and very
> > > often required copying the whole data.
> > > 
> > > Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> > > ---
> > > Changes for v2:
> > > - Adjust exynos_tmu.c code to the newest ti-soc-thermal repository
> > > - Usage of of-thermal.c exported trip points table
> > > Changes for v3:
> > > - Adding exynos_of_get_soc_type() method to set SOC type from
> > > device's compatible string
> > > - "samsung,tmu_" prefix for TMU specific properties has been added
> > > 
> > > ---
> > >  drivers/thermal/samsung/Makefile     |   2 -
> > >  drivers/thermal/samsung/exynos_tmu.c | 345
> > > +++++++++++++++++++++++------------
> > > drivers/thermal/samsung/exynos_tmu.h |  53 +----- 3 files changed,
> > > 226 insertions(+), 174 deletions(-)
> > > 
> > > diff --git a/drivers/thermal/samsung/Makefile
> > > b/drivers/thermal/samsung/Makefile index c09d830..1e47d0d 100644
> > > --- a/drivers/thermal/samsung/Makefile
> > > +++ b/drivers/thermal/samsung/Makefile
> > > @@ -3,5 +3,3 @@
> > >  #
> > >  obj-$(CONFIG_EXYNOS_THERMAL)			+=
> > > exynos_thermal.o exynos_thermal-y				:=
> > > exynos_tmu.o -exynos_thermal-y				+=
> > > exynos_tmu_data.o
> > 
> > Can this makefile change be part of the patch that removes
> > exynos_tmu_data.c?
> > 
> > > -exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE)	+=
> > > exynos_thermal_common.o
> > 
> > Can this makefile change be part of the patch that removes
> > exynos_thermal_common.c?
> 
> Unfortunately, this code cannot be moved to the next patch, in which I
> remove the files, since this causes build break of the series.
> 
> The code structure as is, provides working, bisectable thermal
> solution - thermal and cpu_cooling functionality is preserved across
> all commits in the series.

My concern here is simply that this specific commit is leaving unused files in the tree.

One option would be to remove the files altogether in this specific
commit.

> 
> > 
> > > diff --git a/drivers/thermal/samsung/exynos_tmu.c
> > > b/drivers/thermal/samsung/exynos_tmu.c index ae30f6a..633a9e2 100644
> > > --- a/drivers/thermal/samsung/exynos_tmu.c
> > > +++ b/drivers/thermal/samsung/exynos_tmu.c
> > > @@ -1,6 +1,10 @@
> > >  /*
> > >   * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit)
> > >   *
> > > + *  Copyright (C) 2014 Samsung Electronics
> > > + *  Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> > > + *  Lukasz Majewski <l.majewski@samsung.com>
> > > + *
> > >   *  Copyright (C) 2011 Samsung Electronics
> > >   *  Donggeun Kim <dg77.kim@samsung.com>
> > >   *  Amit Daniel Kachhap <amit.kachhap@linaro.org>
> > > @@ -31,8 +35,8 @@
> > >  #include <linux/platform_device.h>
> > >  #include <linux/regulator/consumer.h>
> > >  
> > > -#include "exynos_thermal_common.h"
> > >  #include "exynos_tmu.h"
> > > +#include "../thermal_core.h"
> > >  
> > >  /* Exynos generic registers */
> > >  #define EXYNOS_TMU_REG_TRIMINFO		0x0
> > > @@ -115,6 +119,7 @@
> > >  #define EXYNOS5440_TMU_TH_RISE4_SHIFT		24
> > >  #define EXYNOS5440_EFUSE_SWAP_OFFSET		8
> > >  
> > > +#define MCELSIUS	1000
> > >  /**
> > >   * struct exynos_tmu_data : A structure to hold the private data
> > > of the TMU driver
> > > @@ -150,7 +155,8 @@ struct exynos_tmu_data {
> > >  	struct clk *clk, *clk_sec;
> > >  	u8 temp_error1, temp_error2;
> > >  	struct regulator *regulator;
> > > -	struct thermal_sensor_conf *reg_conf;
> > > +	struct thermal_zone_device *tzd;
> > > +
> > >  	int (*tmu_initialize)(struct platform_device *pdev);
> > >  	void (*tmu_control)(struct platform_device *pdev, bool on);
> > >  	int (*tmu_read)(struct exynos_tmu_data *data);
> > > @@ -159,6 +165,33 @@ struct exynos_tmu_data {
> > >  	void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
> > >  };
> > >  
> > > +static void exynos_report_trigger(struct exynos_tmu_data *p)
> > > +{
> > > +	char data[10], *envp[] = { data, NULL };
> > > +	struct thermal_zone_device *tz = p->tzd;
> > > +	unsigned long temp;
> > > +	unsigned int i;
> > > +
> > > +	if (!p) {
> > > +		pr_err("Wrong temperature configuration data\n");
> > > +		return;
> > > +	}
> > > +
> > > +	thermal_zone_device_update(tz);
> > > +
> > > +	mutex_lock(&tz->lock);
> > > +	/* Find the level for which trip happened */
> > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > +		tz->ops->get_trip_temp(tz, i, &temp);
> > > +		if (tz->last_temperature < temp)
> > > +			break;
> > > +	}
> > > +
> > > +	snprintf(data, sizeof(data), "%u", i);
> > > +	kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, envp);
> > > +	mutex_unlock(&tz->lock);
> > > +}
> > > +
> > >  /*
> > >   * TMU treats temperature as a mapped temperature code.
> > >   * The temperature is converted differently depending on the
> > > calibration type. @@ -234,14 +267,25 @@ static void
> > > sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info) 
> > >  static u32 get_th_reg(struct exynos_tmu_data *data, u32 threshold,
> > > bool falling) {
> > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > +	struct thermal_zone_device *tz = data->tzd;
> > > +	const struct thermal_trip * const trips =
> > > +		of_thermal_get_trip_points(tz);
> > > +	unsigned long temp;
> > >  	int i;
> > >  
> > > -	for (i = 0; i < pdata->non_hw_trigger_levels; i++) {
> > > -		u8 temp = pdata->trigger_levels[i];
> > > +	if (!trips) {
> > > +		pr_err("%s: Cannot get trip points from
> > > of-thermal.c!\n",
> > > +		       __func__);
> > > +		return 0;
> > > +	}
> > > +
> > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > +		if (trips[i].type == THERMAL_TRIP_CRITICAL)
> > > +			continue;
> > >  
> > > +		temp = trips[i].temperature / MCELSIUS;
> > >  		if (falling)
> > > -			temp -= pdata->threshold_falling;
> > > +			temp -= (trips[i].hysteresis / MCELSIUS);
> > >  		else
> > >  			threshold &= ~(0xff << 8 * i);
> > >  
> > > @@ -305,9 +349,19 @@ static void exynos_tmu_control(struct
> > > platform_device *pdev, bool on) static int
> > > exynos4210_tmu_initialize(struct platform_device *pdev) {
> > >  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > -	unsigned int status;
> > > +	struct thermal_zone_device *tz = data->tzd;
> > > +	const struct thermal_trip * const trips =
> > > +		of_thermal_get_trip_points(tz);
> > >  	int ret = 0, threshold_code, i;
> > > +	unsigned long reference, temp;
> > > +	unsigned int status;
> > > +
> > > +	if (!trips) {
> > > +		pr_err("%s: Cannot get trip points from
> > > of-thermal.c!\n",
> > > +		       __func__);
> > > +		ret = -ENODEV;
> > > +		goto out;
> > > +	}
> > >  
> > >  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> > >  	if (!status) {
> > > @@ -318,12 +372,19 @@ static int exynos4210_tmu_initialize(struct
> > > platform_device *pdev) sanitize_temp_error(data, readl(data->base +
> > > EXYNOS_TMU_REG_TRIMINFO)); 
> > >  	/* Write temperature code for threshold */
> > > -	threshold_code = temp_to_code(data, pdata->threshold);
> > > +	reference = trips[0].temperature / MCELSIUS;
> > > +	threshold_code = temp_to_code(data, reference);
> > > +	if (threshold_code < 0) {
> > > +		ret = threshold_code;
> > > +		goto out;
> > > +	}
> > >  	writeb(threshold_code, data->base +
> > > EXYNOS4210_TMU_REG_THRESHOLD_TEMP); 
> > > -	for (i = 0; i < pdata->non_hw_trigger_levels; i++)
> > > -		writeb(pdata->trigger_levels[i], data->base +
> > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > +		temp = trips[i].temperature / MCELSIUS;
> > > +		writeb(temp - reference, data->base +
> > >  		       EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
> > > +	}
> > >  
> > >  	data->tmu_clear_irqs(data);
> > >  out:
> > > @@ -333,9 +394,11 @@ out:
> > >  static int exynos4412_tmu_initialize(struct platform_device *pdev)
> > >  {
> > >  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > +	const struct thermal_trip * const trips =
> > > +		of_thermal_get_trip_points(data->tzd);
> > >  	unsigned int status, trim_info, con, ctrl,
> > > rising_threshold; int ret = 0, threshold_code, i;
> > > +	unsigned long crit_temp = 0;
> > >  
> > >  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> > >  	if (!status) {
> > > @@ -373,17 +436,29 @@ static int exynos4412_tmu_initialize(struct
> > > platform_device *pdev) data->tmu_clear_irqs(data);
> > >  
> > >  	/* if last threshold limit is also present */
> > > -	i = pdata->max_trigger_level - 1;
> > > -	if (pdata->trigger_levels[i] && pdata->trigger_type[i] ==
> > > HW_TRIP) {
> > > -		threshold_code = temp_to_code(data,
> > > pdata->trigger_levels[i]);
> > > -		/* 1-4 level to be assigned in th0 reg */
> > > -		rising_threshold &= ~(0xff << 8 * i);
> > > -		rising_threshold |= threshold_code << 8 * i;
> > > -		writel(rising_threshold, data->base +
> > > EXYNOS_THD_TEMP_RISE);
> > > -		con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
> > > -		con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > > -		writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> > > +	for (i = 0; i < of_thermal_get_ntrips(data->tzd); i++) {
> > > +		if (trips[i].type == THERMAL_TRIP_CRITICAL) {
> > > +			crit_temp = trips[i].temperature;
> > > +			break;
> > > +		}
> > >  	}
> > > +
> > > +	if (i == of_thermal_get_ntrips(data->tzd)) {
> > > +		pr_err("%s: No CRITICAL trip point defined at
> > > of-thermal.c!\n",
> > > +		       __func__);
> > > +		ret = -EINVAL;
> > > +		goto out;
> > > +	}
> > > +
> > > +	threshold_code = temp_to_code(data, crit_temp / MCELSIUS);
> > > +	/* 1-4 level to be assigned in th0 reg */
> > > +	rising_threshold &= ~(0xff << 8 * i);
> > > +	rising_threshold |= threshold_code << 8 * i;
> > > +	writel(rising_threshold, data->base +
> > > EXYNOS_THD_TEMP_RISE);
> > > +	con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
> > > +	con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > > +	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> > > +
> > >  out:
> > >  	return ret;
> > >  }
> > > @@ -391,9 +466,9 @@ out:
> > >  static int exynos5440_tmu_initialize(struct platform_device *pdev)
> > >  {
> > >  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > >  	unsigned int trim_info = 0, con, rising_threshold;
> > > -	int ret = 0, threshold_code, i;
> > > +	int ret = 0, threshold_code;
> > > +	unsigned long crit_temp = 0;
> > >  
> > >  	/*
> > >  	 * For exynos5440 soc triminfo value is swapped between
> > > TMU0 and @@ -422,9 +497,8 @@ static int
> > > exynos5440_tmu_initialize(struct platform_device *pdev)
> > > data->tmu_clear_irqs(data); 
> > >  	/* if last threshold limit is also present */
> > > -	i = pdata->max_trigger_level - 1;
> > > -	if (pdata->trigger_levels[i] && pdata->trigger_type[i] ==
> > > HW_TRIP) {
> > > -		threshold_code = temp_to_code(data,
> > > pdata->trigger_levels[i]);
> > > +	if (!data->tzd->ops->get_crit_temp(data->tzd, &crit_temp))
> > > {
> > > +		threshold_code = temp_to_code(data, crit_temp /
> > > MCELSIUS); /* 5th level to be assigned in th2 reg */
> > >  		rising_threshold =
> > >  			threshold_code <<
> > > EXYNOS5440_TMU_TH_RISE4_SHIFT; @@ -442,7 +516,7 @@ static int
> > > exynos5440_tmu_initialize(struct platform_device *pdev) static void
> > > exynos4210_tmu_control(struct platform_device *pdev, bool on) {
> > >  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > +	struct thermal_zone_device *tz = data->tzd;
> > >  	unsigned int con, interrupt_en;
> > >  
> > >  	con = get_con_reg(data, readl(data->base +
> > > EXYNOS_TMU_REG_CONTROL)); @@ -450,10 +524,15 @@ static void
> > > exynos4210_tmu_control(struct platform_device *pdev, bool on) if
> > > (on) { con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > >  		interrupt_en =
> > > -			pdata->trigger_enable[3] <<
> > > EXYNOS_TMU_INTEN_RISE3_SHIFT |
> > > -			pdata->trigger_enable[2] <<
> > > EXYNOS_TMU_INTEN_RISE2_SHIFT |
> > > -			pdata->trigger_enable[1] <<
> > > EXYNOS_TMU_INTEN_RISE1_SHIFT |
> > > -			pdata->trigger_enable[0] <<
> > > EXYNOS_TMU_INTEN_RISE0_SHIFT;
> > > +			(of_thermal_is_trip_valid(tz, 3)
> > > +			 << EXYNOS_TMU_INTEN_RISE3_SHIFT) |
> > > +			(of_thermal_is_trip_valid(tz, 2)
> > > +			 << EXYNOS_TMU_INTEN_RISE2_SHIFT) |
> > > +			(of_thermal_is_trip_valid(tz, 1)
> > > +			 << EXYNOS_TMU_INTEN_RISE1_SHIFT) |
> > > +			(of_thermal_is_trip_valid(tz, 0)
> > > +			 << EXYNOS_TMU_INTEN_RISE0_SHIFT);
> > > +
> > >  		if (data->soc != SOC_ARCH_EXYNOS4210)
> > >  			interrupt_en |=
> > >  				interrupt_en <<
> > > EXYNOS_TMU_INTEN_FALL0_SHIFT; @@ -468,7 +547,7 @@ static void
> > > exynos4210_tmu_control(struct platform_device *pdev, bool on)
> > > static void exynos5440_tmu_control(struct platform_device *pdev,
> > > bool on) { struct exynos_tmu_data *data =
> > > platform_get_drvdata(pdev);
> > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > +	struct thermal_zone_device *tz = data->tzd;
> > >  	unsigned int con, interrupt_en;
> > >  
> > >  	con = get_con_reg(data, readl(data->base +
> > > EXYNOS5440_TMU_S0_7_CTRL)); @@ -476,11 +555,16 @@ static void
> > > exynos5440_tmu_control(struct platform_device *pdev, bool on) if
> > > (on) { con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > >  		interrupt_en =
> > > -			pdata->trigger_enable[3] <<
> > > EXYNOS5440_TMU_INTEN_RISE3_SHIFT |
> > > -			pdata->trigger_enable[2] <<
> > > EXYNOS5440_TMU_INTEN_RISE2_SHIFT |
> > > -			pdata->trigger_enable[1] <<
> > > EXYNOS5440_TMU_INTEN_RISE1_SHIFT |
> > > -			pdata->trigger_enable[0] <<
> > > EXYNOS5440_TMU_INTEN_RISE0_SHIFT;
> > > -		interrupt_en |= interrupt_en <<
> > > EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
> > > +			(of_thermal_is_trip_valid(tz, 3)
> > > +			 << EXYNOS5440_TMU_INTEN_RISE3_SHIFT) |
> > > +			(of_thermal_is_trip_valid(tz, 2)
> > > +			 << EXYNOS5440_TMU_INTEN_RISE2_SHIFT) |
> > > +			(of_thermal_is_trip_valid(tz, 1)
> > > +			 << EXYNOS5440_TMU_INTEN_RISE1_SHIFT) |
> > > +			(of_thermal_is_trip_valid(tz, 0)
> > > +			 << EXYNOS5440_TMU_INTEN_RISE0_SHIFT);
> > > +		interrupt_en |=
> > > +			interrupt_en <<
> > > EXYNOS5440_TMU_INTEN_FALL0_SHIFT; } else {
> > >  		con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > >  		interrupt_en = 0; /* Disable all interrupts */
> > > @@ -489,19 +573,22 @@ static void exynos5440_tmu_control(struct
> > > platform_device *pdev, bool on) writel(con, data->base +
> > > EXYNOS5440_TMU_S0_7_CTRL); }
> > >  
> > > -static int exynos_tmu_read(struct exynos_tmu_data *data)
> > > +int exynos_get_temp(void *p, long *temp)
> > >  {
> > > -	int ret;
> > > +	struct exynos_tmu_data *data = p;
> > > +
> > > +	if (!data)
> > > +		return -EINVAL;
> > >  
> > >  	mutex_lock(&data->lock);
> > >  	clk_enable(data->clk);
> > > -	ret = data->tmu_read(data);
> > > -	if (ret >= 0)
> > > -		ret = code_to_temp(data, ret);
> > > +
> > > +	*temp = code_to_temp(data, data->tmu_read(data)) *
> > > MCELSIUS; +
> > >  	clk_disable(data->clk);
> > >  	mutex_unlock(&data->lock);
> > >  
> > > -	return ret;
> > > +	return 0;
> > >  }
> > >  
> > >  #ifdef CONFIG_THERMAL_EMULATION
> > > @@ -613,7 +700,7 @@ static void exynos_tmu_work(struct work_struct
> > > *work) if (!IS_ERR(data->clk_sec))
> > >  		clk_disable(data->clk_sec);
> > >  
> > > -	exynos_report_trigger(data->reg_conf);
> > > +	exynos_report_trigger(data);
> > >  	mutex_lock(&data->lock);
> > >  	clk_enable(data->clk);
> > >  
> > > @@ -673,55 +760,89 @@ static irqreturn_t exynos_tmu_irq(int irq,
> > > void *id) static const struct of_device_id exynos_tmu_match[] = {
> > >  	{
> > >  		.compatible = "samsung,exynos3250-tmu",
> > > -		.data = &exynos3250_default_tmu_data,
> > >  	},
> > >  	{
> > >  		.compatible = "samsung,exynos4210-tmu",
> > > -		.data = &exynos4210_default_tmu_data,
> > >  	},
> > >  	{
> > >  		.compatible = "samsung,exynos4412-tmu",
> > > -		.data = &exynos4412_default_tmu_data,
> > >  	},
> > >  	{
> > >  		.compatible = "samsung,exynos5250-tmu",
> > > -		.data = &exynos5250_default_tmu_data,
> > >  	},
> > >  	{
> > >  		.compatible = "samsung,exynos5260-tmu",
> > > -		.data = &exynos5260_default_tmu_data,
> > >  	},
> > >  	{
> > >  		.compatible = "samsung,exynos5420-tmu",
> > > -		.data = &exynos5420_default_tmu_data,
> > >  	},
> > >  	{
> > >  		.compatible =
> > > "samsung,exynos5420-tmu-ext-triminfo",
> > > -		.data = &exynos5420_default_tmu_data,
> > >  	},
> > >  	{
> > >  		.compatible = "samsung,exynos5440-tmu",
> > > -		.data = &exynos5440_default_tmu_data,
> > >  	},
> > >  	{},
> > >  };
> > >  MODULE_DEVICE_TABLE(of, exynos_tmu_match);
> > >  
> > > -static inline struct  exynos_tmu_platform_data
> > > *exynos_get_driver_data(
> > > -			struct platform_device *pdev, int id)
> > > +static int exynos_of_get_soc_type(struct device_node *np)
> > >  {
> > > -	struct  exynos_tmu_init_data *data_table;
> > > -	struct exynos_tmu_platform_data *tmu_data;
> > > -	const struct of_device_id *match;
> > > +	if (of_device_is_compatible(np, "samsung,exynos3250-tmu"))
> > > +		return SOC_ARCH_EXYNOS3250;
> > > +	else if (of_device_is_compatible(np,
> > > "samsung,exynos4210-tmu"))
> > > +		return SOC_ARCH_EXYNOS4210;
> > > +	else if (of_device_is_compatible(np,
> > > "samsung,exynos4412-tmu"))
> > > +		return SOC_ARCH_EXYNOS4412;
> > > +	else if (of_device_is_compatible(np,
> > > "samsung,exynos5250-tmu"))
> > > +		return SOC_ARCH_EXYNOS5250;
> > > +	else if (of_device_is_compatible(np,
> > > "samsung,exynos5260-tmu"))
> > > +		return SOC_ARCH_EXYNOS5260;
> > > +	else if (of_device_is_compatible(np,
> > > "samsung,exynos5420-tmu"))
> > > +		return SOC_ARCH_EXYNOS5420;
> > > +	else if (of_device_is_compatible(np,
> > > +
> > > "samsung,exynos5420-tmu-ext-triminfo"))
> > > +		return SOC_ARCH_EXYNOS5420_TRIMINFO;
> > > +	else if (of_device_is_compatible(np,
> > > "samsung,exynos5440-tmu"))
> > > +		return SOC_ARCH_EXYNOS5440;
> > > +
> > > +	return -EINVAL;
> > > +}
> > >  
> > > -	match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
> > > -	if (!match)
> > > -		return NULL;
> > > -	data_table = (struct exynos_tmu_init_data *) match->data;
> > > -	if (!data_table || id >= data_table->tmu_count)
> > > -		return NULL;
> > > -	tmu_data = data_table->tmu_data;
> > > -	return (struct exynos_tmu_platform_data *) (tmu_data + id);
> > > +static int exynos_of_sensor_conf(struct device_node *np,
> > > +				 struct exynos_tmu_platform_data
> > > *pdata) +{
> > > +	u32 value;
> > > +	int ret;
> > > +
> > > +	of_node_get(np);
> > > +
> > > +	ret = of_property_read_u32(np, "samsung,tmu_gain", &value);
> > > +	pdata->gain = (u8) value;
> > > +	of_property_read_u32(np, "samsung,tmu_reference_voltage",
> > > &value);
> > > +	pdata->reference_voltage = (u8) value;
> > > +	of_property_read_u32(np, "samsung,tmu_noise_cancel_mode",
> > > &value);
> > > +	pdata->noise_cancel_mode = (u8) value;
> > > +
> > > +	of_property_read_u32(np, "samsung,tmu_efuse_value",
> > > +			     &pdata->efuse_value);
> > > +	of_property_read_u32(np, "samsung,tmu_min_efuse_value",
> > > +			     &pdata->min_efuse_value);
> > > +	of_property_read_u32(np, "samsung,tmu_max_efuse_value",
> > > +			     &pdata->max_efuse_value);
> > > +
> > > +	of_property_read_u32(np, "samsung,tmu_first_point_trim",
> > > &value);
> > > +	pdata->first_point_trim = (u8) value;
> > > +	of_property_read_u32(np, "samsung,tmu_second_point_trim",
> > > &value);
> > > +	pdata->second_point_trim = (u8) value;
> > > +	of_property_read_u32(np,
> > > "samsung,tmu_default_temp_offset", &value);
> > > +	pdata->default_temp_offset = (u8) value;
> > > +
> > > +	of_property_read_u32(np, "samsung,tmu_cal_type",
> > > &pdata->cal_type);
> > > +	of_property_read_u32(np, "samsung,tmu_cal_mode",
> > > &pdata->cal_mode); +
> > > +	of_node_put(np);
> > > +	return 0;
> > >  }
> > >  
> > >  static int exynos_map_dt_data(struct platform_device *pdev)
> > > @@ -771,14 +892,15 @@ static int exynos_map_dt_data(struct
> > > platform_device *pdev) return -EADDRNOTAVAIL;
> > >  	}
> > >  
> > > -	pdata = exynos_get_driver_data(pdev, data->id);
> > > -	if (!pdata) {
> > > -		dev_err(&pdev->dev, "No platform init data
> > > supplied.\n");
> > > -		return -ENODEV;
> > > -	}
> > > +	pdata = devm_kzalloc(&pdev->dev,
> > > +			     sizeof(struct
> > > exynos_tmu_platform_data),
> > > +			     GFP_KERNEL);
> > > +	if (!pdata)
> > > +		return -ENOMEM;
> > >  
> > > +	exynos_of_sensor_conf(pdev->dev.of_node, pdata);
> > >  	data->pdata = pdata;
> > > -	data->soc = pdata->type;
> > > +	data->soc = exynos_of_get_soc_type(pdev->dev.of_node);
> > >  
> > >  	switch (data->soc) {
> > >  	case SOC_ARCH_EXYNOS4210:
> > > @@ -834,12 +956,16 @@ static int exynos_map_dt_data(struct
> > > platform_device *pdev) return 0;
> > >  }
> > >  
> > > +static struct thermal_zone_of_device_ops exynos_sensor_ops = {
> > > +	.get_temp = exynos_get_temp,
> > > +	.set_emul_temp = exynos_tmu_set_emulation,
> > > +};
> > > +
> > >  static int exynos_tmu_probe(struct platform_device *pdev)
> > >  {
> > > -	struct exynos_tmu_data *data;
> > >  	struct exynos_tmu_platform_data *pdata;
> > > -	struct thermal_sensor_conf *sensor_conf;
> > > -	int ret, i;
> > > +	struct exynos_tmu_data *data;
> > > +	int ret;
> > >  
> > >  	data = devm_kzalloc(&pdev->dev, sizeof(struct
> > > exynos_tmu_data), GFP_KERNEL);
> > > @@ -849,9 +975,15 @@ static int exynos_tmu_probe(struct
> > > platform_device *pdev) platform_set_drvdata(pdev, data);
> > >  	mutex_init(&data->lock);
> > >  
> > > +	data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0,
> > > data,
> > > +
> > > &exynos_sensor_ops);
> > > +	if (IS_ERR(data->tzd)) {
> > > +		pr_err("thermal: tz: %p ERROR\n", data->tzd);
> > > +		return PTR_ERR(data->tzd);
> > > +	}
> > >  	ret = exynos_map_dt_data(pdev);
> > >  	if (ret)
> > > -		return ret;
> > > +		goto err_sensor;
> > >  
> > >  	pdata = data->pdata;
> > >  
> > > @@ -860,20 +992,22 @@ static int exynos_tmu_probe(struct
> > > platform_device *pdev) data->clk = devm_clk_get(&pdev->dev,
> > > "tmu_apbif"); if (IS_ERR(data->clk)) {
> > >  		dev_err(&pdev->dev, "Failed to get clock\n");
> > > -		return  PTR_ERR(data->clk);
> > > +		ret = PTR_ERR(data->clk);
> > > +		goto err_sensor;
> > >  	}
> > >  
> > >  	data->clk_sec = devm_clk_get(&pdev->dev,
> > > "tmu_triminfo_apbif"); if (IS_ERR(data->clk_sec)) {
> > >  		if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) {
> > >  			dev_err(&pdev->dev, "Failed to get
> > > triminfo clock\n");
> > > -			return PTR_ERR(data->clk_sec);
> > > +			ret = PTR_ERR(data->clk_sec);
> > > +			goto err_sensor;
> > >  		}
> > >  	} else {
> > >  		ret = clk_prepare(data->clk_sec);
> > >  		if (ret) {
> > >  			dev_err(&pdev->dev, "Failed to get
> > > clock\n");
> > > -			return ret;
> > > +			goto err_sensor;
> > >  		}
> > >  	}
> > >  
> > > @@ -889,45 +1023,6 @@ static int exynos_tmu_probe(struct
> > > platform_device *pdev) goto err_clk;
> > >  	}
> > >  
> > > -	exynos_tmu_control(pdev, true);
> > > -
> > > -	/* Allocate a structure to register with the exynos core
> > > thermal */
> > > -	sensor_conf = devm_kzalloc(&pdev->dev,
> > > -				sizeof(struct
> > > thermal_sensor_conf), GFP_KERNEL);
> > > -	if (!sensor_conf) {
> > > -		ret = -ENOMEM;
> > > -		goto err_clk;
> > > -	}
> > > -	sprintf(sensor_conf->name, "therm_zone%d", data->id);
> > > -	sensor_conf->read_temperature = (int (*)(void
> > > *))exynos_tmu_read;
> > > -	sensor_conf->write_emul_temp =
> > > -		(int (*)(void *, unsigned
> > > long))exynos_tmu_set_emulation;
> > > -	sensor_conf->driver_data = data;
> > > -	sensor_conf->trip_data.trip_count =
> > > pdata->trigger_enable[0] +
> > > -			pdata->trigger_enable[1] +
> > > pdata->trigger_enable[2]+
> > > -			pdata->trigger_enable[3];
> > > -
> > > -	for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
> > > -		sensor_conf->trip_data.trip_val[i] =
> > > -			pdata->threshold +
> > > pdata->trigger_levels[i];
> > > -		sensor_conf->trip_data.trip_type[i] =
> > > -					pdata->trigger_type[i];
> > > -	}
> > > -
> > > -	sensor_conf->trip_data.trigger_falling =
> > > pdata->threshold_falling; -
> > > -	sensor_conf->dev = &pdev->dev;
> > > -	/* Register the sensor with thermal management interface */
> > > -	ret = exynos_register_thermal(sensor_conf);
> > > -	if (ret) {
> > > -		if (ret != -EPROBE_DEFER)
> > > -			dev_err(&pdev->dev,
> > > -				"Failed to register thermal
> > > interface: %d\n",
> > > -				ret);
> > > -		goto err_clk;
> > > -	}
> > > -	data->reg_conf = sensor_conf;
> > > -
> > >  	ret = devm_request_irq(&pdev->dev, data->irq,
> > > exynos_tmu_irq, IRQF_TRIGGER_RISING | IRQF_SHARED,
> > > dev_name(&pdev->dev), data); if (ret) {
> > > @@ -935,21 +1030,31 @@ static int exynos_tmu_probe(struct
> > > platform_device *pdev) goto err_clk;
> > >  	}
> > >  
> > > +	ret = exynos_tmu_initialize(pdev);
> > > +	if (ret) {
> > > +		dev_err(&pdev->dev, "Failed to initialize TMU\n");
> > > +		goto err_clk;
> > > +	}
> > > +	exynos_tmu_control(pdev, true);
> > >  	return 0;
> > > +
> > >  err_clk:
> > >  	clk_unprepare(data->clk);
> > >  err_clk_sec:
> > >  	if (!IS_ERR(data->clk_sec))
> > >  		clk_unprepare(data->clk_sec);
> > > +err_sensor:
> > > +	thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
> > > +
> > >  	return ret;
> > >  }
> > >  
> > >  static int exynos_tmu_remove(struct platform_device *pdev)
> > >  {
> > >  	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > > +	struct thermal_zone_device *tzd = data->tzd;
> > >  
> > > -	exynos_unregister_thermal(data->reg_conf);
> > > -
> > > +	thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
> > >  	exynos_tmu_control(pdev, false);
> > >  
> > >  	clk_unprepare(data->clk);
> > > diff --git a/drivers/thermal/samsung/exynos_tmu.h
> > > b/drivers/thermal/samsung/exynos_tmu.h index 627dec9..d876d4c 100644
> > > --- a/drivers/thermal/samsung/exynos_tmu.h
> > > +++ b/drivers/thermal/samsung/exynos_tmu.h
> > > @@ -23,8 +23,7 @@
> > >  #ifndef _EXYNOS_TMU_H
> > >  #define _EXYNOS_TMU_H
> > >  #include <linux/cpu_cooling.h>
> > > -
> > > -#include "exynos_thermal_common.h"
> > > +#include <dt-bindings/thermal/thermal_exynos.h>
> > >  
> > >  enum soc_type {
> > >  	SOC_ARCH_EXYNOS3250 = 1,
> > > @@ -36,38 +35,9 @@ enum soc_type {
> > >  	SOC_ARCH_EXYNOS5420_TRIMINFO,
> > >  	SOC_ARCH_EXYNOS5440,
> > >  };
> > > -#include <dt-bindings/thermal/thermal_exynos.h>
> > >  
> > >  /**
> > >   * struct exynos_tmu_platform_data
> > > - * @threshold: basic temperature for generating interrupt
> > > - *	       25 <= threshold <= 125 [unit: degree Celsius]
> > > - * @threshold_falling: differntial value for setting threshold
> > > - *		       of temperature falling interrupt.
> > > - * @trigger_levels: array for each interrupt levels
> > > - *	[unit: degree Celsius]
> > > - *	0: temperature for trigger_level0 interrupt
> > > - *	   condition for trigger_level0 interrupt:
> > > - *		current temperature > threshold +
> > > trigger_levels[0]
> > > - *	1: temperature for trigger_level1 interrupt
> > > - *	   condition for trigger_level1 interrupt:
> > > - *		current temperature > threshold +
> > > trigger_levels[1]
> > > - *	2: temperature for trigger_level2 interrupt
> > > - *	   condition for trigger_level2 interrupt:
> > > - *		current temperature > threshold +
> > > trigger_levels[2]
> > > - *	3: temperature for trigger_level3 interrupt
> > > - *	   condition for trigger_level3 interrupt:
> > > - *		current temperature > threshold +
> > > trigger_levels[3]
> > > - * @trigger_type: defines the type of trigger. Possible values are,
> > > - *	THROTTLE_ACTIVE trigger type
> > > - *	THROTTLE_PASSIVE trigger type
> > > - *	SW_TRIP trigger type
> > > - *	HW_TRIP
> > > - * @trigger_enable[]: array to denote which trigger levels are
> > > enabled.
> > > - *	1 = enable trigger_level[] interrupt,
> > > - *	0 = disable trigger_level[] interrupt
> > > - * @max_trigger_level: max trigger level supported by the TMU
> > > - * @non_hw_trigger_levels: number of defined non-hardware trigger
> > > levels
> > >   * @gain: gain of amplifier in the positive-TC generator block
> > >   *	0 < gain <= 15
> > >   * @reference_voltage: reference voltage of amplifier
> > > @@ -79,21 +49,12 @@ enum soc_type {
> > >   * @efuse_value: platform defined fuse value
> > >   * @min_efuse_value: minimum valid trimming data
> > >   * @max_efuse_value: maximum valid trimming data
> > > - * @first_point_trim: temp value of the first point trimming
> > > - * @second_point_trim: temp value of the second point trimming
> > >   * @default_temp_offset: default temperature offset in case of no
> > > trimming
> > >   * @cal_type: calibration type for temperature
> > >   *
> > >   * This structure is required for configuration of exynos_tmu
> > > driver. */
> > >  struct exynos_tmu_platform_data {
> > > -	u8 threshold;
> > > -	u8 threshold_falling;
> > > -	u8 trigger_levels[MAX_TRIP_COUNT];
> > > -	enum trigger_type trigger_type[MAX_TRIP_COUNT];
> > > -	bool trigger_enable[MAX_TRIP_COUNT];
> > > -	u8 max_trigger_level;
> > > -	u8 non_hw_trigger_levels;
> > >  	u8 gain;
> > >  	u8 reference_voltage;
> > >  	u8 noise_cancel_mode;
> > > @@ -110,18 +71,6 @@ struct exynos_tmu_platform_data {
> > >  	u32 cal_mode;
> > >  };
> > >  
> > > -/**
> > > - * struct exynos_tmu_init_data
> > > - * @tmu_count: number of TMU instances.
> > > - * @tmu_data: platform data of all TMU instances.
> > > - * This structure is required to store data for multi-instance
> > > exynos tmu
> > > - * driver.
> > > - */
> > > -struct exynos_tmu_init_data {
> > > -	int tmu_count;
> > > -	struct exynos_tmu_platform_data tmu_data[];
> > > -};
> > > -
> > >  extern struct exynos_tmu_init_data const
> > > exynos3250_default_tmu_data; extern struct exynos_tmu_init_data
> > > const exynos4210_default_tmu_data; extern struct
> > > exynos_tmu_init_data const exynos4412_default_tmu_data; -- 
> > > 2.0.0.rc2
> > > 
> 
> 
> 
> -- 
> Best regards,
> 
> Lukasz Majewski
> 
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Lukasz Majewski Jan. 21, 2015, 8:10 a.m. UTC | #4
Hi Eduardo,

> On Thu, Jan 15, 2015 at 04:17:52PM +0100, Lukasz Majewski wrote:
> > Hi Eduardo,
> > 
> > > On Wed, Jan 14, 2015 at 02:41:12PM +0100, Lukasz Majewski wrote:
> > > > This patch brings support for providing configuration via device
> > > > tree. Previously this data has been hardcoded in the
> > > > exynos_tmu_data.c file. Such approach was not scalable and very
> > > > often required copying the whole data.
> > > > 
> > > > Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> > > > ---
> > > > Changes for v2:
> > > > - Adjust exynos_tmu.c code to the newest ti-soc-thermal
> > > > repository
> > > > - Usage of of-thermal.c exported trip points table
> > > > Changes for v3:
> > > > - Adding exynos_of_get_soc_type() method to set SOC type from
> > > > device's compatible string
> > > > - "samsung,tmu_" prefix for TMU specific properties has been
> > > > added
> > > > 
> > > > ---
> > > >  drivers/thermal/samsung/Makefile     |   2 -
> > > >  drivers/thermal/samsung/exynos_tmu.c | 345
> > > > +++++++++++++++++++++++------------
> > > > drivers/thermal/samsung/exynos_tmu.h |  53 +----- 3 files
> > > > changed, 226 insertions(+), 174 deletions(-)
> > > > 
> > > > diff --git a/drivers/thermal/samsung/Makefile
> > > > b/drivers/thermal/samsung/Makefile index c09d830..1e47d0d 100644
> > > > --- a/drivers/thermal/samsung/Makefile
> > > > +++ b/drivers/thermal/samsung/Makefile
> > > > @@ -3,5 +3,3 @@
> > > >  #
> > > >  obj-$(CONFIG_EXYNOS_THERMAL)			+=
> > > > exynos_thermal.o
> > > > exynos_thermal-y				:= exynos_tmu.o
> > > > -exynos_thermal-y				+=
> > > > exynos_tmu_data.o
> > > 
> > > Can this makefile change be part of the patch that removes
> > > exynos_tmu_data.c?
> > > 
> > > > -exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE)	+=
> > > > exynos_thermal_common.o
> > > 
> > > Can this makefile change be part of the patch that removes
> > > exynos_thermal_common.c?
> > 
> > Unfortunately, this code cannot be moved to the next patch, in
> > which I remove the files, since this causes build break of the
> > series.
> > 
> > The code structure as is, provides working, bisectable thermal
> > solution - thermal and cpu_cooling functionality is preserved across
> > all commits in the series.
> 
> My concern here is simply that this specific commit is leaving unused
> files in the tree.
> 
> One option would be to remove the files altogether in this specific
> commit.

Is is really necessary?

This patch itself changes around 400 LOC. Those changes __are__
important and in my opinion deserve their own commit.

When I squash following patches, which remove old exynos files, we
would have around 1.2K LOC in a single commit.

I think that current approach is far more readable. 

Eduardo, is there a chance for this series (the newest version is v5 -
which include Ablibash comments) to be included to yours -next tree
before v3.19 is out?

> 
> > 
> > > 
> > > > diff --git a/drivers/thermal/samsung/exynos_tmu.c
> > > > b/drivers/thermal/samsung/exynos_tmu.c index ae30f6a..633a9e2
> > > > 100644 --- a/drivers/thermal/samsung/exynos_tmu.c
> > > > +++ b/drivers/thermal/samsung/exynos_tmu.c
> > > > @@ -1,6 +1,10 @@
> > > >  /*
> > > >   * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit)
> > > >   *
> > > > + *  Copyright (C) 2014 Samsung Electronics
> > > > + *  Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> > > > + *  Lukasz Majewski <l.majewski@samsung.com>
> > > > + *
> > > >   *  Copyright (C) 2011 Samsung Electronics
> > > >   *  Donggeun Kim <dg77.kim@samsung.com>
> > > >   *  Amit Daniel Kachhap <amit.kachhap@linaro.org>
> > > > @@ -31,8 +35,8 @@
> > > >  #include <linux/platform_device.h>
> > > >  #include <linux/regulator/consumer.h>
> > > >  
> > > > -#include "exynos_thermal_common.h"
> > > >  #include "exynos_tmu.h"
> > > > +#include "../thermal_core.h"
> > > >  
> > > >  /* Exynos generic registers */
> > > >  #define EXYNOS_TMU_REG_TRIMINFO		0x0
> > > > @@ -115,6 +119,7 @@
> > > >  #define EXYNOS5440_TMU_TH_RISE4_SHIFT		24
> > > >  #define EXYNOS5440_EFUSE_SWAP_OFFSET		8
> > > >  
> > > > +#define MCELSIUS	1000
> > > >  /**
> > > >   * struct exynos_tmu_data : A structure to hold the private
> > > > data of the TMU driver
> > > > @@ -150,7 +155,8 @@ struct exynos_tmu_data {
> > > >  	struct clk *clk, *clk_sec;
> > > >  	u8 temp_error1, temp_error2;
> > > >  	struct regulator *regulator;
> > > > -	struct thermal_sensor_conf *reg_conf;
> > > > +	struct thermal_zone_device *tzd;
> > > > +
> > > >  	int (*tmu_initialize)(struct platform_device *pdev);
> > > >  	void (*tmu_control)(struct platform_device *pdev, bool
> > > > on); int (*tmu_read)(struct exynos_tmu_data *data);
> > > > @@ -159,6 +165,33 @@ struct exynos_tmu_data {
> > > >  	void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
> > > >  };
> > > >  
> > > > +static void exynos_report_trigger(struct exynos_tmu_data *p)
> > > > +{
> > > > +	char data[10], *envp[] = { data, NULL };
> > > > +	struct thermal_zone_device *tz = p->tzd;
> > > > +	unsigned long temp;
> > > > +	unsigned int i;
> > > > +
> > > > +	if (!p) {
> > > > +		pr_err("Wrong temperature configuration
> > > > data\n");
> > > > +		return;
> > > > +	}
> > > > +
> > > > +	thermal_zone_device_update(tz);
> > > > +
> > > > +	mutex_lock(&tz->lock);
> > > > +	/* Find the level for which trip happened */
> > > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > > +		tz->ops->get_trip_temp(tz, i, &temp);
> > > > +		if (tz->last_temperature < temp)
> > > > +			break;
> > > > +	}
> > > > +
> > > > +	snprintf(data, sizeof(data), "%u", i);
> > > > +	kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE,
> > > > envp);
> > > > +	mutex_unlock(&tz->lock);
> > > > +}
> > > > +
> > > >  /*
> > > >   * TMU treats temperature as a mapped temperature code.
> > > >   * The temperature is converted differently depending on the
> > > > calibration type. @@ -234,14 +267,25 @@ static void
> > > > sanitize_temp_error(struct exynos_tmu_data *data, u32
> > > > trim_info) static u32 get_th_reg(struct exynos_tmu_data *data,
> > > > u32 threshold, bool falling) {
> > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > +	struct thermal_zone_device *tz = data->tzd;
> > > > +	const struct thermal_trip * const trips =
> > > > +		of_thermal_get_trip_points(tz);
> > > > +	unsigned long temp;
> > > >  	int i;
> > > >  
> > > > -	for (i = 0; i < pdata->non_hw_trigger_levels; i++) {
> > > > -		u8 temp = pdata->trigger_levels[i];
> > > > +	if (!trips) {
> > > > +		pr_err("%s: Cannot get trip points from
> > > > of-thermal.c!\n",
> > > > +		       __func__);
> > > > +		return 0;
> > > > +	}
> > > > +
> > > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > > +		if (trips[i].type == THERMAL_TRIP_CRITICAL)
> > > > +			continue;
> > > >  
> > > > +		temp = trips[i].temperature / MCELSIUS;
> > > >  		if (falling)
> > > > -			temp -= pdata->threshold_falling;
> > > > +			temp -= (trips[i].hysteresis /
> > > > MCELSIUS); else
> > > >  			threshold &= ~(0xff << 8 * i);
> > > >  
> > > > @@ -305,9 +349,19 @@ static void exynos_tmu_control(struct
> > > > platform_device *pdev, bool on) static int
> > > > exynos4210_tmu_initialize(struct platform_device *pdev) {
> > > >  	struct exynos_tmu_data *data =
> > > > platform_get_drvdata(pdev);
> > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > -	unsigned int status;
> > > > +	struct thermal_zone_device *tz = data->tzd;
> > > > +	const struct thermal_trip * const trips =
> > > > +		of_thermal_get_trip_points(tz);
> > > >  	int ret = 0, threshold_code, i;
> > > > +	unsigned long reference, temp;
> > > > +	unsigned int status;
> > > > +
> > > > +	if (!trips) {
> > > > +		pr_err("%s: Cannot get trip points from
> > > > of-thermal.c!\n",
> > > > +		       __func__);
> > > > +		ret = -ENODEV;
> > > > +		goto out;
> > > > +	}
> > > >  
> > > >  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> > > >  	if (!status) {
> > > > @@ -318,12 +372,19 @@ static int
> > > > exynos4210_tmu_initialize(struct platform_device *pdev)
> > > > sanitize_temp_error(data, readl(data->base +
> > > > EXYNOS_TMU_REG_TRIMINFO)); /* Write temperature code for
> > > > threshold */
> > > > -	threshold_code = temp_to_code(data, pdata->threshold);
> > > > +	reference = trips[0].temperature / MCELSIUS;
> > > > +	threshold_code = temp_to_code(data, reference);
> > > > +	if (threshold_code < 0) {
> > > > +		ret = threshold_code;
> > > > +		goto out;
> > > > +	}
> > > >  	writeb(threshold_code, data->base +
> > > > EXYNOS4210_TMU_REG_THRESHOLD_TEMP); 
> > > > -	for (i = 0; i < pdata->non_hw_trigger_levels; i++)
> > > > -		writeb(pdata->trigger_levels[i], data->base +
> > > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > > +		temp = trips[i].temperature / MCELSIUS;
> > > > +		writeb(temp - reference, data->base +
> > > >  		       EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
> > > > +	}
> > > >  
> > > >  	data->tmu_clear_irqs(data);
> > > >  out:
> > > > @@ -333,9 +394,11 @@ out:
> > > >  static int exynos4412_tmu_initialize(struct platform_device
> > > > *pdev) {
> > > >  	struct exynos_tmu_data *data =
> > > > platform_get_drvdata(pdev);
> > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > +	const struct thermal_trip * const trips =
> > > > +		of_thermal_get_trip_points(data->tzd);
> > > >  	unsigned int status, trim_info, con, ctrl,
> > > > rising_threshold; int ret = 0, threshold_code, i;
> > > > +	unsigned long crit_temp = 0;
> > > >  
> > > >  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> > > >  	if (!status) {
> > > > @@ -373,17 +436,29 @@ static int
> > > > exynos4412_tmu_initialize(struct platform_device *pdev)
> > > > data->tmu_clear_irqs(data); 
> > > >  	/* if last threshold limit is also present */
> > > > -	i = pdata->max_trigger_level - 1;
> > > > -	if (pdata->trigger_levels[i] && pdata->trigger_type[i]
> > > > == HW_TRIP) {
> > > > -		threshold_code = temp_to_code(data,
> > > > pdata->trigger_levels[i]);
> > > > -		/* 1-4 level to be assigned in th0 reg */
> > > > -		rising_threshold &= ~(0xff << 8 * i);
> > > > -		rising_threshold |= threshold_code << 8 * i;
> > > > -		writel(rising_threshold, data->base +
> > > > EXYNOS_THD_TEMP_RISE);
> > > > -		con = readl(data->base +
> > > > EXYNOS_TMU_REG_CONTROL);
> > > > -		con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > > > -		writel(con, data->base +
> > > > EXYNOS_TMU_REG_CONTROL);
> > > > +	for (i = 0; i < of_thermal_get_ntrips(data->tzd); i++)
> > > > {
> > > > +		if (trips[i].type == THERMAL_TRIP_CRITICAL) {
> > > > +			crit_temp = trips[i].temperature;
> > > > +			break;
> > > > +		}
> > > >  	}
> > > > +
> > > > +	if (i == of_thermal_get_ntrips(data->tzd)) {
> > > > +		pr_err("%s: No CRITICAL trip point defined at
> > > > of-thermal.c!\n",
> > > > +		       __func__);
> > > > +		ret = -EINVAL;
> > > > +		goto out;
> > > > +	}
> > > > +
> > > > +	threshold_code = temp_to_code(data, crit_temp /
> > > > MCELSIUS);
> > > > +	/* 1-4 level to be assigned in th0 reg */
> > > > +	rising_threshold &= ~(0xff << 8 * i);
> > > > +	rising_threshold |= threshold_code << 8 * i;
> > > > +	writel(rising_threshold, data->base +
> > > > EXYNOS_THD_TEMP_RISE);
> > > > +	con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
> > > > +	con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > > > +	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> > > > +
> > > >  out:
> > > >  	return ret;
> > > >  }
> > > > @@ -391,9 +466,9 @@ out:
> > > >  static int exynos5440_tmu_initialize(struct platform_device
> > > > *pdev) {
> > > >  	struct exynos_tmu_data *data =
> > > > platform_get_drvdata(pdev);
> > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > >  	unsigned int trim_info = 0, con, rising_threshold;
> > > > -	int ret = 0, threshold_code, i;
> > > > +	int ret = 0, threshold_code;
> > > > +	unsigned long crit_temp = 0;
> > > >  
> > > >  	/*
> > > >  	 * For exynos5440 soc triminfo value is swapped between
> > > > TMU0 and @@ -422,9 +497,8 @@ static int
> > > > exynos5440_tmu_initialize(struct platform_device *pdev)
> > > > data->tmu_clear_irqs(data); 
> > > >  	/* if last threshold limit is also present */
> > > > -	i = pdata->max_trigger_level - 1;
> > > > -	if (pdata->trigger_levels[i] && pdata->trigger_type[i]
> > > > == HW_TRIP) {
> > > > -		threshold_code = temp_to_code(data,
> > > > pdata->trigger_levels[i]);
> > > > +	if (!data->tzd->ops->get_crit_temp(data->tzd,
> > > > &crit_temp)) {
> > > > +		threshold_code = temp_to_code(data, crit_temp /
> > > > MCELSIUS); /* 5th level to be assigned in th2 reg */
> > > >  		rising_threshold =
> > > >  			threshold_code <<
> > > > EXYNOS5440_TMU_TH_RISE4_SHIFT; @@ -442,7 +516,7 @@ static int
> > > > exynos5440_tmu_initialize(struct platform_device *pdev) static
> > > > void exynos4210_tmu_control(struct platform_device *pdev, bool
> > > > on) { struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > +	struct thermal_zone_device *tz = data->tzd;
> > > >  	unsigned int con, interrupt_en;
> > > >  
> > > >  	con = get_con_reg(data, readl(data->base +
> > > > EXYNOS_TMU_REG_CONTROL)); @@ -450,10 +524,15 @@ static void
> > > > exynos4210_tmu_control(struct platform_device *pdev, bool on) if
> > > > (on) { con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > > >  		interrupt_en =
> > > > -			pdata->trigger_enable[3] <<
> > > > EXYNOS_TMU_INTEN_RISE3_SHIFT |
> > > > -			pdata->trigger_enable[2] <<
> > > > EXYNOS_TMU_INTEN_RISE2_SHIFT |
> > > > -			pdata->trigger_enable[1] <<
> > > > EXYNOS_TMU_INTEN_RISE1_SHIFT |
> > > > -			pdata->trigger_enable[0] <<
> > > > EXYNOS_TMU_INTEN_RISE0_SHIFT;
> > > > +			(of_thermal_is_trip_valid(tz, 3)
> > > > +			 << EXYNOS_TMU_INTEN_RISE3_SHIFT) |
> > > > +			(of_thermal_is_trip_valid(tz, 2)
> > > > +			 << EXYNOS_TMU_INTEN_RISE2_SHIFT) |
> > > > +			(of_thermal_is_trip_valid(tz, 1)
> > > > +			 << EXYNOS_TMU_INTEN_RISE1_SHIFT) |
> > > > +			(of_thermal_is_trip_valid(tz, 0)
> > > > +			 << EXYNOS_TMU_INTEN_RISE0_SHIFT);
> > > > +
> > > >  		if (data->soc != SOC_ARCH_EXYNOS4210)
> > > >  			interrupt_en |=
> > > >  				interrupt_en <<
> > > > EXYNOS_TMU_INTEN_FALL0_SHIFT; @@ -468,7 +547,7 @@ static void
> > > > exynos4210_tmu_control(struct platform_device *pdev, bool on)
> > > > static void exynos5440_tmu_control(struct platform_device *pdev,
> > > > bool on) { struct exynos_tmu_data *data =
> > > > platform_get_drvdata(pdev);
> > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > +	struct thermal_zone_device *tz = data->tzd;
> > > >  	unsigned int con, interrupt_en;
> > > >  
> > > >  	con = get_con_reg(data, readl(data->base +
> > > > EXYNOS5440_TMU_S0_7_CTRL)); @@ -476,11 +555,16 @@ static void
> > > > exynos5440_tmu_control(struct platform_device *pdev, bool on) if
> > > > (on) { con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > > >  		interrupt_en =
> > > > -			pdata->trigger_enable[3] <<
> > > > EXYNOS5440_TMU_INTEN_RISE3_SHIFT |
> > > > -			pdata->trigger_enable[2] <<
> > > > EXYNOS5440_TMU_INTEN_RISE2_SHIFT |
> > > > -			pdata->trigger_enable[1] <<
> > > > EXYNOS5440_TMU_INTEN_RISE1_SHIFT |
> > > > -			pdata->trigger_enable[0] <<
> > > > EXYNOS5440_TMU_INTEN_RISE0_SHIFT;
> > > > -		interrupt_en |= interrupt_en <<
> > > > EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
> > > > +			(of_thermal_is_trip_valid(tz, 3)
> > > > +			 << EXYNOS5440_TMU_INTEN_RISE3_SHIFT) |
> > > > +			(of_thermal_is_trip_valid(tz, 2)
> > > > +			 << EXYNOS5440_TMU_INTEN_RISE2_SHIFT) |
> > > > +			(of_thermal_is_trip_valid(tz, 1)
> > > > +			 << EXYNOS5440_TMU_INTEN_RISE1_SHIFT) |
> > > > +			(of_thermal_is_trip_valid(tz, 0)
> > > > +			 << EXYNOS5440_TMU_INTEN_RISE0_SHIFT);
> > > > +		interrupt_en |=
> > > > +			interrupt_en <<
> > > > EXYNOS5440_TMU_INTEN_FALL0_SHIFT; } else {
> > > >  		con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > > >  		interrupt_en = 0; /* Disable all interrupts */
> > > > @@ -489,19 +573,22 @@ static void exynos5440_tmu_control(struct
> > > > platform_device *pdev, bool on) writel(con, data->base +
> > > > EXYNOS5440_TMU_S0_7_CTRL); }
> > > >  
> > > > -static int exynos_tmu_read(struct exynos_tmu_data *data)
> > > > +int exynos_get_temp(void *p, long *temp)
> > > >  {
> > > > -	int ret;
> > > > +	struct exynos_tmu_data *data = p;
> > > > +
> > > > +	if (!data)
> > > > +		return -EINVAL;
> > > >  
> > > >  	mutex_lock(&data->lock);
> > > >  	clk_enable(data->clk);
> > > > -	ret = data->tmu_read(data);
> > > > -	if (ret >= 0)
> > > > -		ret = code_to_temp(data, ret);
> > > > +
> > > > +	*temp = code_to_temp(data, data->tmu_read(data)) *
> > > > MCELSIUS; +
> > > >  	clk_disable(data->clk);
> > > >  	mutex_unlock(&data->lock);
> > > >  
> > > > -	return ret;
> > > > +	return 0;
> > > >  }
> > > >  
> > > >  #ifdef CONFIG_THERMAL_EMULATION
> > > > @@ -613,7 +700,7 @@ static void exynos_tmu_work(struct
> > > > work_struct *work) if (!IS_ERR(data->clk_sec))
> > > >  		clk_disable(data->clk_sec);
> > > >  
> > > > -	exynos_report_trigger(data->reg_conf);
> > > > +	exynos_report_trigger(data);
> > > >  	mutex_lock(&data->lock);
> > > >  	clk_enable(data->clk);
> > > >  
> > > > @@ -673,55 +760,89 @@ static irqreturn_t exynos_tmu_irq(int irq,
> > > > void *id) static const struct of_device_id exynos_tmu_match[] =
> > > > { {
> > > >  		.compatible = "samsung,exynos3250-tmu",
> > > > -		.data = &exynos3250_default_tmu_data,
> > > >  	},
> > > >  	{
> > > >  		.compatible = "samsung,exynos4210-tmu",
> > > > -		.data = &exynos4210_default_tmu_data,
> > > >  	},
> > > >  	{
> > > >  		.compatible = "samsung,exynos4412-tmu",
> > > > -		.data = &exynos4412_default_tmu_data,
> > > >  	},
> > > >  	{
> > > >  		.compatible = "samsung,exynos5250-tmu",
> > > > -		.data = &exynos5250_default_tmu_data,
> > > >  	},
> > > >  	{
> > > >  		.compatible = "samsung,exynos5260-tmu",
> > > > -		.data = &exynos5260_default_tmu_data,
> > > >  	},
> > > >  	{
> > > >  		.compatible = "samsung,exynos5420-tmu",
> > > > -		.data = &exynos5420_default_tmu_data,
> > > >  	},
> > > >  	{
> > > >  		.compatible =
> > > > "samsung,exynos5420-tmu-ext-triminfo",
> > > > -		.data = &exynos5420_default_tmu_data,
> > > >  	},
> > > >  	{
> > > >  		.compatible = "samsung,exynos5440-tmu",
> > > > -		.data = &exynos5440_default_tmu_data,
> > > >  	},
> > > >  	{},
> > > >  };
> > > >  MODULE_DEVICE_TABLE(of, exynos_tmu_match);
> > > >  
> > > > -static inline struct  exynos_tmu_platform_data
> > > > *exynos_get_driver_data(
> > > > -			struct platform_device *pdev, int id)
> > > > +static int exynos_of_get_soc_type(struct device_node *np)
> > > >  {
> > > > -	struct  exynos_tmu_init_data *data_table;
> > > > -	struct exynos_tmu_platform_data *tmu_data;
> > > > -	const struct of_device_id *match;
> > > > +	if (of_device_is_compatible(np,
> > > > "samsung,exynos3250-tmu"))
> > > > +		return SOC_ARCH_EXYNOS3250;
> > > > +	else if (of_device_is_compatible(np,
> > > > "samsung,exynos4210-tmu"))
> > > > +		return SOC_ARCH_EXYNOS4210;
> > > > +	else if (of_device_is_compatible(np,
> > > > "samsung,exynos4412-tmu"))
> > > > +		return SOC_ARCH_EXYNOS4412;
> > > > +	else if (of_device_is_compatible(np,
> > > > "samsung,exynos5250-tmu"))
> > > > +		return SOC_ARCH_EXYNOS5250;
> > > > +	else if (of_device_is_compatible(np,
> > > > "samsung,exynos5260-tmu"))
> > > > +		return SOC_ARCH_EXYNOS5260;
> > > > +	else if (of_device_is_compatible(np,
> > > > "samsung,exynos5420-tmu"))
> > > > +		return SOC_ARCH_EXYNOS5420;
> > > > +	else if (of_device_is_compatible(np,
> > > > +
> > > > "samsung,exynos5420-tmu-ext-triminfo"))
> > > > +		return SOC_ARCH_EXYNOS5420_TRIMINFO;
> > > > +	else if (of_device_is_compatible(np,
> > > > "samsung,exynos5440-tmu"))
> > > > +		return SOC_ARCH_EXYNOS5440;
> > > > +
> > > > +	return -EINVAL;
> > > > +}
> > > >  
> > > > -	match = of_match_node(exynos_tmu_match,
> > > > pdev->dev.of_node);
> > > > -	if (!match)
> > > > -		return NULL;
> > > > -	data_table = (struct exynos_tmu_init_data *)
> > > > match->data;
> > > > -	if (!data_table || id >= data_table->tmu_count)
> > > > -		return NULL;
> > > > -	tmu_data = data_table->tmu_data;
> > > > -	return (struct exynos_tmu_platform_data *) (tmu_data +
> > > > id); +static int exynos_of_sensor_conf(struct device_node *np,
> > > > +				 struct
> > > > exynos_tmu_platform_data *pdata) +{
> > > > +	u32 value;
> > > > +	int ret;
> > > > +
> > > > +	of_node_get(np);
> > > > +
> > > > +	ret = of_property_read_u32(np, "samsung,tmu_gain",
> > > > &value);
> > > > +	pdata->gain = (u8) value;
> > > > +	of_property_read_u32(np,
> > > > "samsung,tmu_reference_voltage", &value);
> > > > +	pdata->reference_voltage = (u8) value;
> > > > +	of_property_read_u32(np,
> > > > "samsung,tmu_noise_cancel_mode", &value);
> > > > +	pdata->noise_cancel_mode = (u8) value;
> > > > +
> > > > +	of_property_read_u32(np, "samsung,tmu_efuse_value",
> > > > +			     &pdata->efuse_value);
> > > > +	of_property_read_u32(np, "samsung,tmu_min_efuse_value",
> > > > +			     &pdata->min_efuse_value);
> > > > +	of_property_read_u32(np, "samsung,tmu_max_efuse_value",
> > > > +			     &pdata->max_efuse_value);
> > > > +
> > > > +	of_property_read_u32(np,
> > > > "samsung,tmu_first_point_trim", &value);
> > > > +	pdata->first_point_trim = (u8) value;
> > > > +	of_property_read_u32(np,
> > > > "samsung,tmu_second_point_trim", &value);
> > > > +	pdata->second_point_trim = (u8) value;
> > > > +	of_property_read_u32(np,
> > > > "samsung,tmu_default_temp_offset", &value);
> > > > +	pdata->default_temp_offset = (u8) value;
> > > > +
> > > > +	of_property_read_u32(np, "samsung,tmu_cal_type",
> > > > &pdata->cal_type);
> > > > +	of_property_read_u32(np, "samsung,tmu_cal_mode",
> > > > &pdata->cal_mode); +
> > > > +	of_node_put(np);
> > > > +	return 0;
> > > >  }
> > > >  
> > > >  static int exynos_map_dt_data(struct platform_device *pdev)
> > > > @@ -771,14 +892,15 @@ static int exynos_map_dt_data(struct
> > > > platform_device *pdev) return -EADDRNOTAVAIL;
> > > >  	}
> > > >  
> > > > -	pdata = exynos_get_driver_data(pdev, data->id);
> > > > -	if (!pdata) {
> > > > -		dev_err(&pdev->dev, "No platform init data
> > > > supplied.\n");
> > > > -		return -ENODEV;
> > > > -	}
> > > > +	pdata = devm_kzalloc(&pdev->dev,
> > > > +			     sizeof(struct
> > > > exynos_tmu_platform_data),
> > > > +			     GFP_KERNEL);
> > > > +	if (!pdata)
> > > > +		return -ENOMEM;
> > > >  
> > > > +	exynos_of_sensor_conf(pdev->dev.of_node, pdata);
> > > >  	data->pdata = pdata;
> > > > -	data->soc = pdata->type;
> > > > +	data->soc = exynos_of_get_soc_type(pdev->dev.of_node);
> > > >  
> > > >  	switch (data->soc) {
> > > >  	case SOC_ARCH_EXYNOS4210:
> > > > @@ -834,12 +956,16 @@ static int exynos_map_dt_data(struct
> > > > platform_device *pdev) return 0;
> > > >  }
> > > >  
> > > > +static struct thermal_zone_of_device_ops exynos_sensor_ops = {
> > > > +	.get_temp = exynos_get_temp,
> > > > +	.set_emul_temp = exynos_tmu_set_emulation,
> > > > +};
> > > > +
> > > >  static int exynos_tmu_probe(struct platform_device *pdev)
> > > >  {
> > > > -	struct exynos_tmu_data *data;
> > > >  	struct exynos_tmu_platform_data *pdata;
> > > > -	struct thermal_sensor_conf *sensor_conf;
> > > > -	int ret, i;
> > > > +	struct exynos_tmu_data *data;
> > > > +	int ret;
> > > >  
> > > >  	data = devm_kzalloc(&pdev->dev, sizeof(struct
> > > > exynos_tmu_data), GFP_KERNEL);
> > > > @@ -849,9 +975,15 @@ static int exynos_tmu_probe(struct
> > > > platform_device *pdev) platform_set_drvdata(pdev, data);
> > > >  	mutex_init(&data->lock);
> > > >  
> > > > +	data->tzd =
> > > > thermal_zone_of_sensor_register(&pdev->dev, 0, data,
> > > > +
> > > > &exynos_sensor_ops);
> > > > +	if (IS_ERR(data->tzd)) {
> > > > +		pr_err("thermal: tz: %p ERROR\n", data->tzd);
> > > > +		return PTR_ERR(data->tzd);
> > > > +	}
> > > >  	ret = exynos_map_dt_data(pdev);
> > > >  	if (ret)
> > > > -		return ret;
> > > > +		goto err_sensor;
> > > >  
> > > >  	pdata = data->pdata;
> > > >  
> > > > @@ -860,20 +992,22 @@ static int exynos_tmu_probe(struct
> > > > platform_device *pdev) data->clk = devm_clk_get(&pdev->dev,
> > > > "tmu_apbif"); if (IS_ERR(data->clk)) {
> > > >  		dev_err(&pdev->dev, "Failed to get clock\n");
> > > > -		return  PTR_ERR(data->clk);
> > > > +		ret = PTR_ERR(data->clk);
> > > > +		goto err_sensor;
> > > >  	}
> > > >  
> > > >  	data->clk_sec = devm_clk_get(&pdev->dev,
> > > > "tmu_triminfo_apbif"); if (IS_ERR(data->clk_sec)) {
> > > >  		if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO)
> > > > { dev_err(&pdev->dev, "Failed to get
> > > > triminfo clock\n");
> > > > -			return PTR_ERR(data->clk_sec);
> > > > +			ret = PTR_ERR(data->clk_sec);
> > > > +			goto err_sensor;
> > > >  		}
> > > >  	} else {
> > > >  		ret = clk_prepare(data->clk_sec);
> > > >  		if (ret) {
> > > >  			dev_err(&pdev->dev, "Failed to get
> > > > clock\n");
> > > > -			return ret;
> > > > +			goto err_sensor;
> > > >  		}
> > > >  	}
> > > >  
> > > > @@ -889,45 +1023,6 @@ static int exynos_tmu_probe(struct
> > > > platform_device *pdev) goto err_clk;
> > > >  	}
> > > >  
> > > > -	exynos_tmu_control(pdev, true);
> > > > -
> > > > -	/* Allocate a structure to register with the exynos
> > > > core thermal */
> > > > -	sensor_conf = devm_kzalloc(&pdev->dev,
> > > > -				sizeof(struct
> > > > thermal_sensor_conf), GFP_KERNEL);
> > > > -	if (!sensor_conf) {
> > > > -		ret = -ENOMEM;
> > > > -		goto err_clk;
> > > > -	}
> > > > -	sprintf(sensor_conf->name, "therm_zone%d", data->id);
> > > > -	sensor_conf->read_temperature = (int (*)(void
> > > > *))exynos_tmu_read;
> > > > -	sensor_conf->write_emul_temp =
> > > > -		(int (*)(void *, unsigned
> > > > long))exynos_tmu_set_emulation;
> > > > -	sensor_conf->driver_data = data;
> > > > -	sensor_conf->trip_data.trip_count =
> > > > pdata->trigger_enable[0] +
> > > > -			pdata->trigger_enable[1] +
> > > > pdata->trigger_enable[2]+
> > > > -			pdata->trigger_enable[3];
> > > > -
> > > > -	for (i = 0; i < sensor_conf->trip_data.trip_count;
> > > > i++) {
> > > > -		sensor_conf->trip_data.trip_val[i] =
> > > > -			pdata->threshold +
> > > > pdata->trigger_levels[i];
> > > > -		sensor_conf->trip_data.trip_type[i] =
> > > > -					pdata->trigger_type[i];
> > > > -	}
> > > > -
> > > > -	sensor_conf->trip_data.trigger_falling =
> > > > pdata->threshold_falling; -
> > > > -	sensor_conf->dev = &pdev->dev;
> > > > -	/* Register the sensor with thermal management
> > > > interface */
> > > > -	ret = exynos_register_thermal(sensor_conf);
> > > > -	if (ret) {
> > > > -		if (ret != -EPROBE_DEFER)
> > > > -			dev_err(&pdev->dev,
> > > > -				"Failed to register thermal
> > > > interface: %d\n",
> > > > -				ret);
> > > > -		goto err_clk;
> > > > -	}
> > > > -	data->reg_conf = sensor_conf;
> > > > -
> > > >  	ret = devm_request_irq(&pdev->dev, data->irq,
> > > > exynos_tmu_irq, IRQF_TRIGGER_RISING | IRQF_SHARED,
> > > > dev_name(&pdev->dev), data); if (ret) {
> > > > @@ -935,21 +1030,31 @@ static int exynos_tmu_probe(struct
> > > > platform_device *pdev) goto err_clk;
> > > >  	}
> > > >  
> > > > +	ret = exynos_tmu_initialize(pdev);
> > > > +	if (ret) {
> > > > +		dev_err(&pdev->dev, "Failed to initialize
> > > > TMU\n");
> > > > +		goto err_clk;
> > > > +	}
> > > > +	exynos_tmu_control(pdev, true);
> > > >  	return 0;
> > > > +
> > > >  err_clk:
> > > >  	clk_unprepare(data->clk);
> > > >  err_clk_sec:
> > > >  	if (!IS_ERR(data->clk_sec))
> > > >  		clk_unprepare(data->clk_sec);
> > > > +err_sensor:
> > > > +	thermal_zone_of_sensor_unregister(&pdev->dev,
> > > > data->tzd); +
> > > >  	return ret;
> > > >  }
> > > >  
> > > >  static int exynos_tmu_remove(struct platform_device *pdev)
> > > >  {
> > > >  	struct exynos_tmu_data *data =
> > > > platform_get_drvdata(pdev);
> > > > +	struct thermal_zone_device *tzd = data->tzd;
> > > >  
> > > > -	exynos_unregister_thermal(data->reg_conf);
> > > > -
> > > > +	thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
> > > >  	exynos_tmu_control(pdev, false);
> > > >  
> > > >  	clk_unprepare(data->clk);
> > > > diff --git a/drivers/thermal/samsung/exynos_tmu.h
> > > > b/drivers/thermal/samsung/exynos_tmu.h index 627dec9..d876d4c
> > > > 100644 --- a/drivers/thermal/samsung/exynos_tmu.h
> > > > +++ b/drivers/thermal/samsung/exynos_tmu.h
> > > > @@ -23,8 +23,7 @@
> > > >  #ifndef _EXYNOS_TMU_H
> > > >  #define _EXYNOS_TMU_H
> > > >  #include <linux/cpu_cooling.h>
> > > > -
> > > > -#include "exynos_thermal_common.h"
> > > > +#include <dt-bindings/thermal/thermal_exynos.h>
> > > >  
> > > >  enum soc_type {
> > > >  	SOC_ARCH_EXYNOS3250 = 1,
> > > > @@ -36,38 +35,9 @@ enum soc_type {
> > > >  	SOC_ARCH_EXYNOS5420_TRIMINFO,
> > > >  	SOC_ARCH_EXYNOS5440,
> > > >  };
> > > > -#include <dt-bindings/thermal/thermal_exynos.h>
> > > >  
> > > >  /**
> > > >   * struct exynos_tmu_platform_data
> > > > - * @threshold: basic temperature for generating interrupt
> > > > - *	       25 <= threshold <= 125 [unit: degree Celsius]
> > > > - * @threshold_falling: differntial value for setting threshold
> > > > - *		       of temperature falling interrupt.
> > > > - * @trigger_levels: array for each interrupt levels
> > > > - *	[unit: degree Celsius]
> > > > - *	0: temperature for trigger_level0 interrupt
> > > > - *	   condition for trigger_level0 interrupt:
> > > > - *		current temperature > threshold +
> > > > trigger_levels[0]
> > > > - *	1: temperature for trigger_level1 interrupt
> > > > - *	   condition for trigger_level1 interrupt:
> > > > - *		current temperature > threshold +
> > > > trigger_levels[1]
> > > > - *	2: temperature for trigger_level2 interrupt
> > > > - *	   condition for trigger_level2 interrupt:
> > > > - *		current temperature > threshold +
> > > > trigger_levels[2]
> > > > - *	3: temperature for trigger_level3 interrupt
> > > > - *	   condition for trigger_level3 interrupt:
> > > > - *		current temperature > threshold +
> > > > trigger_levels[3]
> > > > - * @trigger_type: defines the type of trigger. Possible values
> > > > are,
> > > > - *	THROTTLE_ACTIVE trigger type
> > > > - *	THROTTLE_PASSIVE trigger type
> > > > - *	SW_TRIP trigger type
> > > > - *	HW_TRIP
> > > > - * @trigger_enable[]: array to denote which trigger levels are
> > > > enabled.
> > > > - *	1 = enable trigger_level[] interrupt,
> > > > - *	0 = disable trigger_level[] interrupt
> > > > - * @max_trigger_level: max trigger level supported by the TMU
> > > > - * @non_hw_trigger_levels: number of defined non-hardware
> > > > trigger levels
> > > >   * @gain: gain of amplifier in the positive-TC generator block
> > > >   *	0 < gain <= 15
> > > >   * @reference_voltage: reference voltage of amplifier
> > > > @@ -79,21 +49,12 @@ enum soc_type {
> > > >   * @efuse_value: platform defined fuse value
> > > >   * @min_efuse_value: minimum valid trimming data
> > > >   * @max_efuse_value: maximum valid trimming data
> > > > - * @first_point_trim: temp value of the first point trimming
> > > > - * @second_point_trim: temp value of the second point trimming
> > > >   * @default_temp_offset: default temperature offset in case of
> > > > no trimming
> > > >   * @cal_type: calibration type for temperature
> > > >   *
> > > >   * This structure is required for configuration of exynos_tmu
> > > > driver. */
> > > >  struct exynos_tmu_platform_data {
> > > > -	u8 threshold;
> > > > -	u8 threshold_falling;
> > > > -	u8 trigger_levels[MAX_TRIP_COUNT];
> > > > -	enum trigger_type trigger_type[MAX_TRIP_COUNT];
> > > > -	bool trigger_enable[MAX_TRIP_COUNT];
> > > > -	u8 max_trigger_level;
> > > > -	u8 non_hw_trigger_levels;
> > > >  	u8 gain;
> > > >  	u8 reference_voltage;
> > > >  	u8 noise_cancel_mode;
> > > > @@ -110,18 +71,6 @@ struct exynos_tmu_platform_data {
> > > >  	u32 cal_mode;
> > > >  };
> > > >  
> > > > -/**
> > > > - * struct exynos_tmu_init_data
> > > > - * @tmu_count: number of TMU instances.
> > > > - * @tmu_data: platform data of all TMU instances.
> > > > - * This structure is required to store data for multi-instance
> > > > exynos tmu
> > > > - * driver.
> > > > - */
> > > > -struct exynos_tmu_init_data {
> > > > -	int tmu_count;
> > > > -	struct exynos_tmu_platform_data tmu_data[];
> > > > -};
> > > > -
> > > >  extern struct exynos_tmu_init_data const
> > > > exynos3250_default_tmu_data; extern struct exynos_tmu_init_data
> > > > const exynos4210_default_tmu_data; extern struct
> > > > exynos_tmu_init_data const exynos4412_default_tmu_data; -- 
> > > > 2.0.0.rc2
> > > > 
> > 
> > 
> > 
> > -- 
> > Best regards,
> > 
> > Lukasz Majewski
> > 
> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Eduardo Valentin Jan. 21, 2015, 9:20 a.m. UTC | #5
On Wed, Jan 21, 2015 at 09:10:15AM +0100, Lukasz Majewski wrote:
> Hi Eduardo,
> 
> > On Thu, Jan 15, 2015 at 04:17:52PM +0100, Lukasz Majewski wrote:
> > > Hi Eduardo,
> > > 
> > > > On Wed, Jan 14, 2015 at 02:41:12PM +0100, Lukasz Majewski wrote:
> > > > > This patch brings support for providing configuration via device
> > > > > tree. Previously this data has been hardcoded in the
> > > > > exynos_tmu_data.c file. Such approach was not scalable and very
> > > > > often required copying the whole data.
> > > > > 
> > > > > Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> > > > > ---
> > > > > Changes for v2:
> > > > > - Adjust exynos_tmu.c code to the newest ti-soc-thermal
> > > > > repository
> > > > > - Usage of of-thermal.c exported trip points table
> > > > > Changes for v3:
> > > > > - Adding exynos_of_get_soc_type() method to set SOC type from
> > > > > device's compatible string
> > > > > - "samsung,tmu_" prefix for TMU specific properties has been
> > > > > added
> > > > > 
> > > > > ---
> > > > >  drivers/thermal/samsung/Makefile     |   2 -
> > > > >  drivers/thermal/samsung/exynos_tmu.c | 345
> > > > > +++++++++++++++++++++++------------
> > > > > drivers/thermal/samsung/exynos_tmu.h |  53 +----- 3 files
> > > > > changed, 226 insertions(+), 174 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/thermal/samsung/Makefile
> > > > > b/drivers/thermal/samsung/Makefile index c09d830..1e47d0d 100644
> > > > > --- a/drivers/thermal/samsung/Makefile
> > > > > +++ b/drivers/thermal/samsung/Makefile
> > > > > @@ -3,5 +3,3 @@
> > > > >  #
> > > > >  obj-$(CONFIG_EXYNOS_THERMAL)			+=
> > > > > exynos_thermal.o
> > > > > exynos_thermal-y				:= exynos_tmu.o
> > > > > -exynos_thermal-y				+=
> > > > > exynos_tmu_data.o
> > > > 
> > > > Can this makefile change be part of the patch that removes
> > > > exynos_tmu_data.c?
> > > > 
> > > > > -exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE)	+=
> > > > > exynos_thermal_common.o
> > > > 
> > > > Can this makefile change be part of the patch that removes
> > > > exynos_thermal_common.c?
> > > 
> > > Unfortunately, this code cannot be moved to the next patch, in
> > > which I remove the files, since this causes build break of the
> > > series.
> > > 
> > > The code structure as is, provides working, bisectable thermal
> > > solution - thermal and cpu_cooling functionality is preserved across
> > > all commits in the series.
> > 
> > My concern here is simply that this specific commit is leaving unused
> > files in the tree.
> > 
> > One option would be to remove the files altogether in this specific
> > commit.
> 
> Is is really necessary?
> 
> This patch itself changes around 400 LOC. Those changes __are__
> important and in my opinion deserve their own commit.
> 
> When I squash following patches, which remove old exynos files, we
> would have around 1.2K LOC in a single commit.
> 
> I think that current approach is far more readable. 

I agree that separating is far more readable. However, the commit leaves
zombie files.

> 
> Eduardo, is there a chance for this series (the newest version is v5 -
> which include Ablibash comments) to be included to yours -next tree
> before v3.19 is out?

Yes, we can target this. I have sent couple of minor comments on v5.
Despite them, there are also some parts of this series that are supposed
to be merged via other trees. The cpufreq part seams to be too little
and Viresh has already flagged that I can merge it as long it is in a
separated patch. However, most part of this series touches arch/arm
directory and those should go via your platform tree. Is there a change
you could either as your Exynos maintainer to queue the patches touching
arch/arm or ask him if he is fine if I merge them via my tree?

Cheers,

> 
> > 
> > > 
> > > > 
> > > > > diff --git a/drivers/thermal/samsung/exynos_tmu.c
> > > > > b/drivers/thermal/samsung/exynos_tmu.c index ae30f6a..633a9e2
> > > > > 100644 --- a/drivers/thermal/samsung/exynos_tmu.c
> > > > > +++ b/drivers/thermal/samsung/exynos_tmu.c
> > > > > @@ -1,6 +1,10 @@
> > > > >  /*
> > > > >   * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit)
> > > > >   *
> > > > > + *  Copyright (C) 2014 Samsung Electronics
> > > > > + *  Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> > > > > + *  Lukasz Majewski <l.majewski@samsung.com>
> > > > > + *
> > > > >   *  Copyright (C) 2011 Samsung Electronics
> > > > >   *  Donggeun Kim <dg77.kim@samsung.com>
> > > > >   *  Amit Daniel Kachhap <amit.kachhap@linaro.org>
> > > > > @@ -31,8 +35,8 @@
> > > > >  #include <linux/platform_device.h>
> > > > >  #include <linux/regulator/consumer.h>
> > > > >  
> > > > > -#include "exynos_thermal_common.h"
> > > > >  #include "exynos_tmu.h"
> > > > > +#include "../thermal_core.h"
> > > > >  
> > > > >  /* Exynos generic registers */
> > > > >  #define EXYNOS_TMU_REG_TRIMINFO		0x0
> > > > > @@ -115,6 +119,7 @@
> > > > >  #define EXYNOS5440_TMU_TH_RISE4_SHIFT		24
> > > > >  #define EXYNOS5440_EFUSE_SWAP_OFFSET		8
> > > > >  
> > > > > +#define MCELSIUS	1000
> > > > >  /**
> > > > >   * struct exynos_tmu_data : A structure to hold the private
> > > > > data of the TMU driver
> > > > > @@ -150,7 +155,8 @@ struct exynos_tmu_data {
> > > > >  	struct clk *clk, *clk_sec;
> > > > >  	u8 temp_error1, temp_error2;
> > > > >  	struct regulator *regulator;
> > > > > -	struct thermal_sensor_conf *reg_conf;
> > > > > +	struct thermal_zone_device *tzd;
> > > > > +
> > > > >  	int (*tmu_initialize)(struct platform_device *pdev);
> > > > >  	void (*tmu_control)(struct platform_device *pdev, bool
> > > > > on); int (*tmu_read)(struct exynos_tmu_data *data);
> > > > > @@ -159,6 +165,33 @@ struct exynos_tmu_data {
> > > > >  	void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
> > > > >  };
> > > > >  
> > > > > +static void exynos_report_trigger(struct exynos_tmu_data *p)
> > > > > +{
> > > > > +	char data[10], *envp[] = { data, NULL };
> > > > > +	struct thermal_zone_device *tz = p->tzd;
> > > > > +	unsigned long temp;
> > > > > +	unsigned int i;
> > > > > +
> > > > > +	if (!p) {
> > > > > +		pr_err("Wrong temperature configuration
> > > > > data\n");
> > > > > +		return;
> > > > > +	}
> > > > > +
> > > > > +	thermal_zone_device_update(tz);
> > > > > +
> > > > > +	mutex_lock(&tz->lock);
> > > > > +	/* Find the level for which trip happened */
> > > > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > > > +		tz->ops->get_trip_temp(tz, i, &temp);
> > > > > +		if (tz->last_temperature < temp)
> > > > > +			break;
> > > > > +	}
> > > > > +
> > > > > +	snprintf(data, sizeof(data), "%u", i);
> > > > > +	kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE,
> > > > > envp);
> > > > > +	mutex_unlock(&tz->lock);
> > > > > +}
> > > > > +
> > > > >  /*
> > > > >   * TMU treats temperature as a mapped temperature code.
> > > > >   * The temperature is converted differently depending on the
> > > > > calibration type. @@ -234,14 +267,25 @@ static void
> > > > > sanitize_temp_error(struct exynos_tmu_data *data, u32
> > > > > trim_info) static u32 get_th_reg(struct exynos_tmu_data *data,
> > > > > u32 threshold, bool falling) {
> > > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > > +	struct thermal_zone_device *tz = data->tzd;
> > > > > +	const struct thermal_trip * const trips =
> > > > > +		of_thermal_get_trip_points(tz);
> > > > > +	unsigned long temp;
> > > > >  	int i;
> > > > >  
> > > > > -	for (i = 0; i < pdata->non_hw_trigger_levels; i++) {
> > > > > -		u8 temp = pdata->trigger_levels[i];
> > > > > +	if (!trips) {
> > > > > +		pr_err("%s: Cannot get trip points from
> > > > > of-thermal.c!\n",
> > > > > +		       __func__);
> > > > > +		return 0;
> > > > > +	}
> > > > > +
> > > > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > > > +		if (trips[i].type == THERMAL_TRIP_CRITICAL)
> > > > > +			continue;
> > > > >  
> > > > > +		temp = trips[i].temperature / MCELSIUS;
> > > > >  		if (falling)
> > > > > -			temp -= pdata->threshold_falling;
> > > > > +			temp -= (trips[i].hysteresis /
> > > > > MCELSIUS); else
> > > > >  			threshold &= ~(0xff << 8 * i);
> > > > >  
> > > > > @@ -305,9 +349,19 @@ static void exynos_tmu_control(struct
> > > > > platform_device *pdev, bool on) static int
> > > > > exynos4210_tmu_initialize(struct platform_device *pdev) {
> > > > >  	struct exynos_tmu_data *data =
> > > > > platform_get_drvdata(pdev);
> > > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > > -	unsigned int status;
> > > > > +	struct thermal_zone_device *tz = data->tzd;
> > > > > +	const struct thermal_trip * const trips =
> > > > > +		of_thermal_get_trip_points(tz);
> > > > >  	int ret = 0, threshold_code, i;
> > > > > +	unsigned long reference, temp;
> > > > > +	unsigned int status;
> > > > > +
> > > > > +	if (!trips) {
> > > > > +		pr_err("%s: Cannot get trip points from
> > > > > of-thermal.c!\n",
> > > > > +		       __func__);
> > > > > +		ret = -ENODEV;
> > > > > +		goto out;
> > > > > +	}
> > > > >  
> > > > >  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> > > > >  	if (!status) {
> > > > > @@ -318,12 +372,19 @@ static int
> > > > > exynos4210_tmu_initialize(struct platform_device *pdev)
> > > > > sanitize_temp_error(data, readl(data->base +
> > > > > EXYNOS_TMU_REG_TRIMINFO)); /* Write temperature code for
> > > > > threshold */
> > > > > -	threshold_code = temp_to_code(data, pdata->threshold);
> > > > > +	reference = trips[0].temperature / MCELSIUS;
> > > > > +	threshold_code = temp_to_code(data, reference);
> > > > > +	if (threshold_code < 0) {
> > > > > +		ret = threshold_code;
> > > > > +		goto out;
> > > > > +	}
> > > > >  	writeb(threshold_code, data->base +
> > > > > EXYNOS4210_TMU_REG_THRESHOLD_TEMP); 
> > > > > -	for (i = 0; i < pdata->non_hw_trigger_levels; i++)
> > > > > -		writeb(pdata->trigger_levels[i], data->base +
> > > > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > > > +		temp = trips[i].temperature / MCELSIUS;
> > > > > +		writeb(temp - reference, data->base +
> > > > >  		       EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
> > > > > +	}
> > > > >  
> > > > >  	data->tmu_clear_irqs(data);
> > > > >  out:
> > > > > @@ -333,9 +394,11 @@ out:
> > > > >  static int exynos4412_tmu_initialize(struct platform_device
> > > > > *pdev) {
> > > > >  	struct exynos_tmu_data *data =
> > > > > platform_get_drvdata(pdev);
> > > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > > +	const struct thermal_trip * const trips =
> > > > > +		of_thermal_get_trip_points(data->tzd);
> > > > >  	unsigned int status, trim_info, con, ctrl,
> > > > > rising_threshold; int ret = 0, threshold_code, i;
> > > > > +	unsigned long crit_temp = 0;
> > > > >  
> > > > >  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> > > > >  	if (!status) {
> > > > > @@ -373,17 +436,29 @@ static int
> > > > > exynos4412_tmu_initialize(struct platform_device *pdev)
> > > > > data->tmu_clear_irqs(data); 
> > > > >  	/* if last threshold limit is also present */
> > > > > -	i = pdata->max_trigger_level - 1;
> > > > > -	if (pdata->trigger_levels[i] && pdata->trigger_type[i]
> > > > > == HW_TRIP) {
> > > > > -		threshold_code = temp_to_code(data,
> > > > > pdata->trigger_levels[i]);
> > > > > -		/* 1-4 level to be assigned in th0 reg */
> > > > > -		rising_threshold &= ~(0xff << 8 * i);
> > > > > -		rising_threshold |= threshold_code << 8 * i;
> > > > > -		writel(rising_threshold, data->base +
> > > > > EXYNOS_THD_TEMP_RISE);
> > > > > -		con = readl(data->base +
> > > > > EXYNOS_TMU_REG_CONTROL);
> > > > > -		con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > > > > -		writel(con, data->base +
> > > > > EXYNOS_TMU_REG_CONTROL);
> > > > > +	for (i = 0; i < of_thermal_get_ntrips(data->tzd); i++)
> > > > > {
> > > > > +		if (trips[i].type == THERMAL_TRIP_CRITICAL) {
> > > > > +			crit_temp = trips[i].temperature;
> > > > > +			break;
> > > > > +		}
> > > > >  	}
> > > > > +
> > > > > +	if (i == of_thermal_get_ntrips(data->tzd)) {
> > > > > +		pr_err("%s: No CRITICAL trip point defined at
> > > > > of-thermal.c!\n",
> > > > > +		       __func__);
> > > > > +		ret = -EINVAL;
> > > > > +		goto out;
> > > > > +	}
> > > > > +
> > > > > +	threshold_code = temp_to_code(data, crit_temp /
> > > > > MCELSIUS);
> > > > > +	/* 1-4 level to be assigned in th0 reg */
> > > > > +	rising_threshold &= ~(0xff << 8 * i);
> > > > > +	rising_threshold |= threshold_code << 8 * i;
> > > > > +	writel(rising_threshold, data->base +
> > > > > EXYNOS_THD_TEMP_RISE);
> > > > > +	con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
> > > > > +	con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > > > > +	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> > > > > +
> > > > >  out:
> > > > >  	return ret;
> > > > >  }
> > > > > @@ -391,9 +466,9 @@ out:
> > > > >  static int exynos5440_tmu_initialize(struct platform_device
> > > > > *pdev) {
> > > > >  	struct exynos_tmu_data *data =
> > > > > platform_get_drvdata(pdev);
> > > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > >  	unsigned int trim_info = 0, con, rising_threshold;
> > > > > -	int ret = 0, threshold_code, i;
> > > > > +	int ret = 0, threshold_code;
> > > > > +	unsigned long crit_temp = 0;
> > > > >  
> > > > >  	/*
> > > > >  	 * For exynos5440 soc triminfo value is swapped between
> > > > > TMU0 and @@ -422,9 +497,8 @@ static int
> > > > > exynos5440_tmu_initialize(struct platform_device *pdev)
> > > > > data->tmu_clear_irqs(data); 
> > > > >  	/* if last threshold limit is also present */
> > > > > -	i = pdata->max_trigger_level - 1;
> > > > > -	if (pdata->trigger_levels[i] && pdata->trigger_type[i]
> > > > > == HW_TRIP) {
> > > > > -		threshold_code = temp_to_code(data,
> > > > > pdata->trigger_levels[i]);
> > > > > +	if (!data->tzd->ops->get_crit_temp(data->tzd,
> > > > > &crit_temp)) {
> > > > > +		threshold_code = temp_to_code(data, crit_temp /
> > > > > MCELSIUS); /* 5th level to be assigned in th2 reg */
> > > > >  		rising_threshold =
> > > > >  			threshold_code <<
> > > > > EXYNOS5440_TMU_TH_RISE4_SHIFT; @@ -442,7 +516,7 @@ static int
> > > > > exynos5440_tmu_initialize(struct platform_device *pdev) static
> > > > > void exynos4210_tmu_control(struct platform_device *pdev, bool
> > > > > on) { struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> > > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > > +	struct thermal_zone_device *tz = data->tzd;
> > > > >  	unsigned int con, interrupt_en;
> > > > >  
> > > > >  	con = get_con_reg(data, readl(data->base +
> > > > > EXYNOS_TMU_REG_CONTROL)); @@ -450,10 +524,15 @@ static void
> > > > > exynos4210_tmu_control(struct platform_device *pdev, bool on) if
> > > > > (on) { con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > > > >  		interrupt_en =
> > > > > -			pdata->trigger_enable[3] <<
> > > > > EXYNOS_TMU_INTEN_RISE3_SHIFT |
> > > > > -			pdata->trigger_enable[2] <<
> > > > > EXYNOS_TMU_INTEN_RISE2_SHIFT |
> > > > > -			pdata->trigger_enable[1] <<
> > > > > EXYNOS_TMU_INTEN_RISE1_SHIFT |
> > > > > -			pdata->trigger_enable[0] <<
> > > > > EXYNOS_TMU_INTEN_RISE0_SHIFT;
> > > > > +			(of_thermal_is_trip_valid(tz, 3)
> > > > > +			 << EXYNOS_TMU_INTEN_RISE3_SHIFT) |
> > > > > +			(of_thermal_is_trip_valid(tz, 2)
> > > > > +			 << EXYNOS_TMU_INTEN_RISE2_SHIFT) |
> > > > > +			(of_thermal_is_trip_valid(tz, 1)
> > > > > +			 << EXYNOS_TMU_INTEN_RISE1_SHIFT) |
> > > > > +			(of_thermal_is_trip_valid(tz, 0)
> > > > > +			 << EXYNOS_TMU_INTEN_RISE0_SHIFT);
> > > > > +
> > > > >  		if (data->soc != SOC_ARCH_EXYNOS4210)
> > > > >  			interrupt_en |=
> > > > >  				interrupt_en <<
> > > > > EXYNOS_TMU_INTEN_FALL0_SHIFT; @@ -468,7 +547,7 @@ static void
> > > > > exynos4210_tmu_control(struct platform_device *pdev, bool on)
> > > > > static void exynos5440_tmu_control(struct platform_device *pdev,
> > > > > bool on) { struct exynos_tmu_data *data =
> > > > > platform_get_drvdata(pdev);
> > > > > -	struct exynos_tmu_platform_data *pdata = data->pdata;
> > > > > +	struct thermal_zone_device *tz = data->tzd;
> > > > >  	unsigned int con, interrupt_en;
> > > > >  
> > > > >  	con = get_con_reg(data, readl(data->base +
> > > > > EXYNOS5440_TMU_S0_7_CTRL)); @@ -476,11 +555,16 @@ static void
> > > > > exynos5440_tmu_control(struct platform_device *pdev, bool on) if
> > > > > (on) { con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > > > >  		interrupt_en =
> > > > > -			pdata->trigger_enable[3] <<
> > > > > EXYNOS5440_TMU_INTEN_RISE3_SHIFT |
> > > > > -			pdata->trigger_enable[2] <<
> > > > > EXYNOS5440_TMU_INTEN_RISE2_SHIFT |
> > > > > -			pdata->trigger_enable[1] <<
> > > > > EXYNOS5440_TMU_INTEN_RISE1_SHIFT |
> > > > > -			pdata->trigger_enable[0] <<
> > > > > EXYNOS5440_TMU_INTEN_RISE0_SHIFT;
> > > > > -		interrupt_en |= interrupt_en <<
> > > > > EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
> > > > > +			(of_thermal_is_trip_valid(tz, 3)
> > > > > +			 << EXYNOS5440_TMU_INTEN_RISE3_SHIFT) |
> > > > > +			(of_thermal_is_trip_valid(tz, 2)
> > > > > +			 << EXYNOS5440_TMU_INTEN_RISE2_SHIFT) |
> > > > > +			(of_thermal_is_trip_valid(tz, 1)
> > > > > +			 << EXYNOS5440_TMU_INTEN_RISE1_SHIFT) |
> > > > > +			(of_thermal_is_trip_valid(tz, 0)
> > > > > +			 << EXYNOS5440_TMU_INTEN_RISE0_SHIFT);
> > > > > +		interrupt_en |=
> > > > > +			interrupt_en <<
> > > > > EXYNOS5440_TMU_INTEN_FALL0_SHIFT; } else {
> > > > >  		con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > > > >  		interrupt_en = 0; /* Disable all interrupts */
> > > > > @@ -489,19 +573,22 @@ static void exynos5440_tmu_control(struct
> > > > > platform_device *pdev, bool on) writel(con, data->base +
> > > > > EXYNOS5440_TMU_S0_7_CTRL); }
> > > > >  
> > > > > -static int exynos_tmu_read(struct exynos_tmu_data *data)
> > > > > +int exynos_get_temp(void *p, long *temp)
> > > > >  {
> > > > > -	int ret;
> > > > > +	struct exynos_tmu_data *data = p;
> > > > > +
> > > > > +	if (!data)
> > > > > +		return -EINVAL;
> > > > >  
> > > > >  	mutex_lock(&data->lock);
> > > > >  	clk_enable(data->clk);
> > > > > -	ret = data->tmu_read(data);
> > > > > -	if (ret >= 0)
> > > > > -		ret = code_to_temp(data, ret);
> > > > > +
> > > > > +	*temp = code_to_temp(data, data->tmu_read(data)) *
> > > > > MCELSIUS; +
> > > > >  	clk_disable(data->clk);
> > > > >  	mutex_unlock(&data->lock);
> > > > >  
> > > > > -	return ret;
> > > > > +	return 0;
> > > > >  }
> > > > >  
> > > > >  #ifdef CONFIG_THERMAL_EMULATION
> > > > > @@ -613,7 +700,7 @@ static void exynos_tmu_work(struct
> > > > > work_struct *work) if (!IS_ERR(data->clk_sec))
> > > > >  		clk_disable(data->clk_sec);
> > > > >  
> > > > > -	exynos_report_trigger(data->reg_conf);
> > > > > +	exynos_report_trigger(data);
> > > > >  	mutex_lock(&data->lock);
> > > > >  	clk_enable(data->clk);
> > > > >  
> > > > > @@ -673,55 +760,89 @@ static irqreturn_t exynos_tmu_irq(int irq,
> > > > > void *id) static const struct of_device_id exynos_tmu_match[] =
> > > > > { {
> > > > >  		.compatible = "samsung,exynos3250-tmu",
> > > > > -		.data = &exynos3250_default_tmu_data,
> > > > >  	},
> > > > >  	{
> > > > >  		.compatible = "samsung,exynos4210-tmu",
> > > > > -		.data = &exynos4210_default_tmu_data,
> > > > >  	},
> > > > >  	{
> > > > >  		.compatible = "samsung,exynos4412-tmu",
> > > > > -		.data = &exynos4412_default_tmu_data,
> > > > >  	},
> > > > >  	{
> > > > >  		.compatible = "samsung,exynos5250-tmu",
> > > > > -		.data = &exynos5250_default_tmu_data,
> > > > >  	},
> > > > >  	{
> > > > >  		.compatible = "samsung,exynos5260-tmu",
> > > > > -		.data = &exynos5260_default_tmu_data,
> > > > >  	},
> > > > >  	{
> > > > >  		.compatible = "samsung,exynos5420-tmu",
> > > > > -		.data = &exynos5420_default_tmu_data,
> > > > >  	},
> > > > >  	{
> > > > >  		.compatible =
> > > > > "samsung,exynos5420-tmu-ext-triminfo",
> > > > > -		.data = &exynos5420_default_tmu_data,
> > > > >  	},
> > > > >  	{
> > > > >  		.compatible = "samsung,exynos5440-tmu",
> > > > > -		.data = &exynos5440_default_tmu_data,
> > > > >  	},
> > > > >  	{},
> > > > >  };
> > > > >  MODULE_DEVICE_TABLE(of, exynos_tmu_match);
> > > > >  
> > > > > -static inline struct  exynos_tmu_platform_data
> > > > > *exynos_get_driver_data(
> > > > > -			struct platform_device *pdev, int id)
> > > > > +static int exynos_of_get_soc_type(struct device_node *np)
> > > > >  {
> > > > > -	struct  exynos_tmu_init_data *data_table;
> > > > > -	struct exynos_tmu_platform_data *tmu_data;
> > > > > -	const struct of_device_id *match;
> > > > > +	if (of_device_is_compatible(np,
> > > > > "samsung,exynos3250-tmu"))
> > > > > +		return SOC_ARCH_EXYNOS3250;
> > > > > +	else if (of_device_is_compatible(np,
> > > > > "samsung,exynos4210-tmu"))
> > > > > +		return SOC_ARCH_EXYNOS4210;
> > > > > +	else if (of_device_is_compatible(np,
> > > > > "samsung,exynos4412-tmu"))
> > > > > +		return SOC_ARCH_EXYNOS4412;
> > > > > +	else if (of_device_is_compatible(np,
> > > > > "samsung,exynos5250-tmu"))
> > > > > +		return SOC_ARCH_EXYNOS5250;
> > > > > +	else if (of_device_is_compatible(np,
> > > > > "samsung,exynos5260-tmu"))
> > > > > +		return SOC_ARCH_EXYNOS5260;
> > > > > +	else if (of_device_is_compatible(np,
> > > > > "samsung,exynos5420-tmu"))
> > > > > +		return SOC_ARCH_EXYNOS5420;
> > > > > +	else if (of_device_is_compatible(np,
> > > > > +
> > > > > "samsung,exynos5420-tmu-ext-triminfo"))
> > > > > +		return SOC_ARCH_EXYNOS5420_TRIMINFO;
> > > > > +	else if (of_device_is_compatible(np,
> > > > > "samsung,exynos5440-tmu"))
> > > > > +		return SOC_ARCH_EXYNOS5440;
> > > > > +
> > > > > +	return -EINVAL;
> > > > > +}
> > > > >  
> > > > > -	match = of_match_node(exynos_tmu_match,
> > > > > pdev->dev.of_node);
> > > > > -	if (!match)
> > > > > -		return NULL;
> > > > > -	data_table = (struct exynos_tmu_init_data *)
> > > > > match->data;
> > > > > -	if (!data_table || id >= data_table->tmu_count)
> > > > > -		return NULL;
> > > > > -	tmu_data = data_table->tmu_data;
> > > > > -	return (struct exynos_tmu_platform_data *) (tmu_data +
> > > > > id); +static int exynos_of_sensor_conf(struct device_node *np,
> > > > > +				 struct
> > > > > exynos_tmu_platform_data *pdata) +{
> > > > > +	u32 value;
> > > > > +	int ret;
> > > > > +
> > > > > +	of_node_get(np);
> > > > > +
> > > > > +	ret = of_property_read_u32(np, "samsung,tmu_gain",
> > > > > &value);
> > > > > +	pdata->gain = (u8) value;
> > > > > +	of_property_read_u32(np,
> > > > > "samsung,tmu_reference_voltage", &value);
> > > > > +	pdata->reference_voltage = (u8) value;
> > > > > +	of_property_read_u32(np,
> > > > > "samsung,tmu_noise_cancel_mode", &value);
> > > > > +	pdata->noise_cancel_mode = (u8) value;
> > > > > +
> > > > > +	of_property_read_u32(np, "samsung,tmu_efuse_value",
> > > > > +			     &pdata->efuse_value);
> > > > > +	of_property_read_u32(np, "samsung,tmu_min_efuse_value",
> > > > > +			     &pdata->min_efuse_value);
> > > > > +	of_property_read_u32(np, "samsung,tmu_max_efuse_value",
> > > > > +			     &pdata->max_efuse_value);
> > > > > +
> > > > > +	of_property_read_u32(np,
> > > > > "samsung,tmu_first_point_trim", &value);
> > > > > +	pdata->first_point_trim = (u8) value;
> > > > > +	of_property_read_u32(np,
> > > > > "samsung,tmu_second_point_trim", &value);
> > > > > +	pdata->second_point_trim = (u8) value;
> > > > > +	of_property_read_u32(np,
> > > > > "samsung,tmu_default_temp_offset", &value);
> > > > > +	pdata->default_temp_offset = (u8) value;
> > > > > +
> > > > > +	of_property_read_u32(np, "samsung,tmu_cal_type",
> > > > > &pdata->cal_type);
> > > > > +	of_property_read_u32(np, "samsung,tmu_cal_mode",
> > > > > &pdata->cal_mode); +
> > > > > +	of_node_put(np);
> > > > > +	return 0;
> > > > >  }
> > > > >  
> > > > >  static int exynos_map_dt_data(struct platform_device *pdev)
> > > > > @@ -771,14 +892,15 @@ static int exynos_map_dt_data(struct
> > > > > platform_device *pdev) return -EADDRNOTAVAIL;
> > > > >  	}
> > > > >  
> > > > > -	pdata = exynos_get_driver_data(pdev, data->id);
> > > > > -	if (!pdata) {
> > > > > -		dev_err(&pdev->dev, "No platform init data
> > > > > supplied.\n");
> > > > > -		return -ENODEV;
> > > > > -	}
> > > > > +	pdata = devm_kzalloc(&pdev->dev,
> > > > > +			     sizeof(struct
> > > > > exynos_tmu_platform_data),
> > > > > +			     GFP_KERNEL);
> > > > > +	if (!pdata)
> > > > > +		return -ENOMEM;
> > > > >  
> > > > > +	exynos_of_sensor_conf(pdev->dev.of_node, pdata);
> > > > >  	data->pdata = pdata;
> > > > > -	data->soc = pdata->type;
> > > > > +	data->soc = exynos_of_get_soc_type(pdev->dev.of_node);
> > > > >  
> > > > >  	switch (data->soc) {
> > > > >  	case SOC_ARCH_EXYNOS4210:
> > > > > @@ -834,12 +956,16 @@ static int exynos_map_dt_data(struct
> > > > > platform_device *pdev) return 0;
> > > > >  }
> > > > >  
> > > > > +static struct thermal_zone_of_device_ops exynos_sensor_ops = {
> > > > > +	.get_temp = exynos_get_temp,
> > > > > +	.set_emul_temp = exynos_tmu_set_emulation,
> > > > > +};
> > > > > +
> > > > >  static int exynos_tmu_probe(struct platform_device *pdev)
> > > > >  {
> > > > > -	struct exynos_tmu_data *data;
> > > > >  	struct exynos_tmu_platform_data *pdata;
> > > > > -	struct thermal_sensor_conf *sensor_conf;
> > > > > -	int ret, i;
> > > > > +	struct exynos_tmu_data *data;
> > > > > +	int ret;
> > > > >  
> > > > >  	data = devm_kzalloc(&pdev->dev, sizeof(struct
> > > > > exynos_tmu_data), GFP_KERNEL);
> > > > > @@ -849,9 +975,15 @@ static int exynos_tmu_probe(struct
> > > > > platform_device *pdev) platform_set_drvdata(pdev, data);
> > > > >  	mutex_init(&data->lock);
> > > > >  
> > > > > +	data->tzd =
> > > > > thermal_zone_of_sensor_register(&pdev->dev, 0, data,
> > > > > +
> > > > > &exynos_sensor_ops);
> > > > > +	if (IS_ERR(data->tzd)) {
> > > > > +		pr_err("thermal: tz: %p ERROR\n", data->tzd);
> > > > > +		return PTR_ERR(data->tzd);
> > > > > +	}
> > > > >  	ret = exynos_map_dt_data(pdev);
> > > > >  	if (ret)
> > > > > -		return ret;
> > > > > +		goto err_sensor;
> > > > >  
> > > > >  	pdata = data->pdata;
> > > > >  
> > > > > @@ -860,20 +992,22 @@ static int exynos_tmu_probe(struct
> > > > > platform_device *pdev) data->clk = devm_clk_get(&pdev->dev,
> > > > > "tmu_apbif"); if (IS_ERR(data->clk)) {
> > > > >  		dev_err(&pdev->dev, "Failed to get clock\n");
> > > > > -		return  PTR_ERR(data->clk);
> > > > > +		ret = PTR_ERR(data->clk);
> > > > > +		goto err_sensor;
> > > > >  	}
> > > > >  
> > > > >  	data->clk_sec = devm_clk_get(&pdev->dev,
> > > > > "tmu_triminfo_apbif"); if (IS_ERR(data->clk_sec)) {
> > > > >  		if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO)
> > > > > { dev_err(&pdev->dev, "Failed to get
> > > > > triminfo clock\n");
> > > > > -			return PTR_ERR(data->clk_sec);
> > > > > +			ret = PTR_ERR(data->clk_sec);
> > > > > +			goto err_sensor;
> > > > >  		}
> > > > >  	} else {
> > > > >  		ret = clk_prepare(data->clk_sec);
> > > > >  		if (ret) {
> > > > >  			dev_err(&pdev->dev, "Failed to get
> > > > > clock\n");
> > > > > -			return ret;
> > > > > +			goto err_sensor;
> > > > >  		}
> > > > >  	}
> > > > >  
> > > > > @@ -889,45 +1023,6 @@ static int exynos_tmu_probe(struct
> > > > > platform_device *pdev) goto err_clk;
> > > > >  	}
> > > > >  
> > > > > -	exynos_tmu_control(pdev, true);
> > > > > -
> > > > > -	/* Allocate a structure to register with the exynos
> > > > > core thermal */
> > > > > -	sensor_conf = devm_kzalloc(&pdev->dev,
> > > > > -				sizeof(struct
> > > > > thermal_sensor_conf), GFP_KERNEL);
> > > > > -	if (!sensor_conf) {
> > > > > -		ret = -ENOMEM;
> > > > > -		goto err_clk;
> > > > > -	}
> > > > > -	sprintf(sensor_conf->name, "therm_zone%d", data->id);
> > > > > -	sensor_conf->read_temperature = (int (*)(void
> > > > > *))exynos_tmu_read;
> > > > > -	sensor_conf->write_emul_temp =
> > > > > -		(int (*)(void *, unsigned
> > > > > long))exynos_tmu_set_emulation;
> > > > > -	sensor_conf->driver_data = data;
> > > > > -	sensor_conf->trip_data.trip_count =
> > > > > pdata->trigger_enable[0] +
> > > > > -			pdata->trigger_enable[1] +
> > > > > pdata->trigger_enable[2]+
> > > > > -			pdata->trigger_enable[3];
> > > > > -
> > > > > -	for (i = 0; i < sensor_conf->trip_data.trip_count;
> > > > > i++) {
> > > > > -		sensor_conf->trip_data.trip_val[i] =
> > > > > -			pdata->threshold +
> > > > > pdata->trigger_levels[i];
> > > > > -		sensor_conf->trip_data.trip_type[i] =
> > > > > -					pdata->trigger_type[i];
> > > > > -	}
> > > > > -
> > > > > -	sensor_conf->trip_data.trigger_falling =
> > > > > pdata->threshold_falling; -
> > > > > -	sensor_conf->dev = &pdev->dev;
> > > > > -	/* Register the sensor with thermal management
> > > > > interface */
> > > > > -	ret = exynos_register_thermal(sensor_conf);
> > > > > -	if (ret) {
> > > > > -		if (ret != -EPROBE_DEFER)
> > > > > -			dev_err(&pdev->dev,
> > > > > -				"Failed to register thermal
> > > > > interface: %d\n",
> > > > > -				ret);
> > > > > -		goto err_clk;
> > > > > -	}
> > > > > -	data->reg_conf = sensor_conf;
> > > > > -
> > > > >  	ret = devm_request_irq(&pdev->dev, data->irq,
> > > > > exynos_tmu_irq, IRQF_TRIGGER_RISING | IRQF_SHARED,
> > > > > dev_name(&pdev->dev), data); if (ret) {
> > > > > @@ -935,21 +1030,31 @@ static int exynos_tmu_probe(struct
> > > > > platform_device *pdev) goto err_clk;
> > > > >  	}
> > > > >  
> > > > > +	ret = exynos_tmu_initialize(pdev);
> > > > > +	if (ret) {
> > > > > +		dev_err(&pdev->dev, "Failed to initialize
> > > > > TMU\n");
> > > > > +		goto err_clk;
> > > > > +	}
> > > > > +	exynos_tmu_control(pdev, true);
> > > > >  	return 0;
> > > > > +
> > > > >  err_clk:
> > > > >  	clk_unprepare(data->clk);
> > > > >  err_clk_sec:
> > > > >  	if (!IS_ERR(data->clk_sec))
> > > > >  		clk_unprepare(data->clk_sec);
> > > > > +err_sensor:
> > > > > +	thermal_zone_of_sensor_unregister(&pdev->dev,
> > > > > data->tzd); +
> > > > >  	return ret;
> > > > >  }
> > > > >  
> > > > >  static int exynos_tmu_remove(struct platform_device *pdev)
> > > > >  {
> > > > >  	struct exynos_tmu_data *data =
> > > > > platform_get_drvdata(pdev);
> > > > > +	struct thermal_zone_device *tzd = data->tzd;
> > > > >  
> > > > > -	exynos_unregister_thermal(data->reg_conf);
> > > > > -
> > > > > +	thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
> > > > >  	exynos_tmu_control(pdev, false);
> > > > >  
> > > > >  	clk_unprepare(data->clk);
> > > > > diff --git a/drivers/thermal/samsung/exynos_tmu.h
> > > > > b/drivers/thermal/samsung/exynos_tmu.h index 627dec9..d876d4c
> > > > > 100644 --- a/drivers/thermal/samsung/exynos_tmu.h
> > > > > +++ b/drivers/thermal/samsung/exynos_tmu.h
> > > > > @@ -23,8 +23,7 @@
> > > > >  #ifndef _EXYNOS_TMU_H
> > > > >  #define _EXYNOS_TMU_H
> > > > >  #include <linux/cpu_cooling.h>
> > > > > -
> > > > > -#include "exynos_thermal_common.h"
> > > > > +#include <dt-bindings/thermal/thermal_exynos.h>
> > > > >  
> > > > >  enum soc_type {
> > > > >  	SOC_ARCH_EXYNOS3250 = 1,
> > > > > @@ -36,38 +35,9 @@ enum soc_type {
> > > > >  	SOC_ARCH_EXYNOS5420_TRIMINFO,
> > > > >  	SOC_ARCH_EXYNOS5440,
> > > > >  };
> > > > > -#include <dt-bindings/thermal/thermal_exynos.h>
> > > > >  
> > > > >  /**
> > > > >   * struct exynos_tmu_platform_data
> > > > > - * @threshold: basic temperature for generating interrupt
> > > > > - *	       25 <= threshold <= 125 [unit: degree Celsius]
> > > > > - * @threshold_falling: differntial value for setting threshold
> > > > > - *		       of temperature falling interrupt.
> > > > > - * @trigger_levels: array for each interrupt levels
> > > > > - *	[unit: degree Celsius]
> > > > > - *	0: temperature for trigger_level0 interrupt
> > > > > - *	   condition for trigger_level0 interrupt:
> > > > > - *		current temperature > threshold +
> > > > > trigger_levels[0]
> > > > > - *	1: temperature for trigger_level1 interrupt
> > > > > - *	   condition for trigger_level1 interrupt:
> > > > > - *		current temperature > threshold +
> > > > > trigger_levels[1]
> > > > > - *	2: temperature for trigger_level2 interrupt
> > > > > - *	   condition for trigger_level2 interrupt:
> > > > > - *		current temperature > threshold +
> > > > > trigger_levels[2]
> > > > > - *	3: temperature for trigger_level3 interrupt
> > > > > - *	   condition for trigger_level3 interrupt:
> > > > > - *		current temperature > threshold +
> > > > > trigger_levels[3]
> > > > > - * @trigger_type: defines the type of trigger. Possible values
> > > > > are,
> > > > > - *	THROTTLE_ACTIVE trigger type
> > > > > - *	THROTTLE_PASSIVE trigger type
> > > > > - *	SW_TRIP trigger type
> > > > > - *	HW_TRIP
> > > > > - * @trigger_enable[]: array to denote which trigger levels are
> > > > > enabled.
> > > > > - *	1 = enable trigger_level[] interrupt,
> > > > > - *	0 = disable trigger_level[] interrupt
> > > > > - * @max_trigger_level: max trigger level supported by the TMU
> > > > > - * @non_hw_trigger_levels: number of defined non-hardware
> > > > > trigger levels
> > > > >   * @gain: gain of amplifier in the positive-TC generator block
> > > > >   *	0 < gain <= 15
> > > > >   * @reference_voltage: reference voltage of amplifier
> > > > > @@ -79,21 +49,12 @@ enum soc_type {
> > > > >   * @efuse_value: platform defined fuse value
> > > > >   * @min_efuse_value: minimum valid trimming data
> > > > >   * @max_efuse_value: maximum valid trimming data
> > > > > - * @first_point_trim: temp value of the first point trimming
> > > > > - * @second_point_trim: temp value of the second point trimming
> > > > >   * @default_temp_offset: default temperature offset in case of
> > > > > no trimming
> > > > >   * @cal_type: calibration type for temperature
> > > > >   *
> > > > >   * This structure is required for configuration of exynos_tmu
> > > > > driver. */
> > > > >  struct exynos_tmu_platform_data {
> > > > > -	u8 threshold;
> > > > > -	u8 threshold_falling;
> > > > > -	u8 trigger_levels[MAX_TRIP_COUNT];
> > > > > -	enum trigger_type trigger_type[MAX_TRIP_COUNT];
> > > > > -	bool trigger_enable[MAX_TRIP_COUNT];
> > > > > -	u8 max_trigger_level;
> > > > > -	u8 non_hw_trigger_levels;
> > > > >  	u8 gain;
> > > > >  	u8 reference_voltage;
> > > > >  	u8 noise_cancel_mode;
> > > > > @@ -110,18 +71,6 @@ struct exynos_tmu_platform_data {
> > > > >  	u32 cal_mode;
> > > > >  };
> > > > >  
> > > > > -/**
> > > > > - * struct exynos_tmu_init_data
> > > > > - * @tmu_count: number of TMU instances.
> > > > > - * @tmu_data: platform data of all TMU instances.
> > > > > - * This structure is required to store data for multi-instance
> > > > > exynos tmu
> > > > > - * driver.
> > > > > - */
> > > > > -struct exynos_tmu_init_data {
> > > > > -	int tmu_count;
> > > > > -	struct exynos_tmu_platform_data tmu_data[];
> > > > > -};
> > > > > -
> > > > >  extern struct exynos_tmu_init_data const
> > > > > exynos3250_default_tmu_data; extern struct exynos_tmu_init_data
> > > > > const exynos4210_default_tmu_data; extern struct
> > > > > exynos_tmu_init_data const exynos4412_default_tmu_data; -- 
> > > > > 2.0.0.rc2
> > > > > 
> > > 
> > > 
> > > 
> > > -- 
> > > Best regards,
> > > 
> > > Lukasz Majewski
> > > 
> > > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
> 
> 
> 
> -- 
> Best regards,
> 
> Lukasz Majewski
> 
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Lukasz Majewski Jan. 22, 2015, 2:17 p.m. UTC | #6
Hi Eduardo,

> On Wed, Jan 21, 2015 at 09:10:15AM +0100, Lukasz Majewski wrote:
> > Hi Eduardo,
> > 
> > > On Thu, Jan 15, 2015 at 04:17:52PM +0100, Lukasz Majewski wrote:
> > > > Hi Eduardo,
> > > > 
> > > > > On Wed, Jan 14, 2015 at 02:41:12PM +0100, Lukasz Majewski
> > > > > wrote:
> > > > > > This patch brings support for providing configuration via
> > > > > > device tree. Previously this data has been hardcoded in the
> > > > > > exynos_tmu_data.c file. Such approach was not scalable and
> > > > > > very often required copying the whole data.
> > > > > > 
> > > > > > Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> > > > > > ---
> > > > > > Changes for v2:
> > > > > > - Adjust exynos_tmu.c code to the newest ti-soc-thermal
> > > > > > repository
> > > > > > - Usage of of-thermal.c exported trip points table
> > > > > > Changes for v3:
> > > > > > - Adding exynos_of_get_soc_type() method to set SOC type
> > > > > > from device's compatible string
> > > > > > - "samsung,tmu_" prefix for TMU specific properties has been
> > > > > > added
> > > > > > 
> > > > > > ---
> > > > > >  drivers/thermal/samsung/Makefile     |   2 -
> > > > > >  drivers/thermal/samsung/exynos_tmu.c | 345
> > > > > > +++++++++++++++++++++++------------
> > > > > > drivers/thermal/samsung/exynos_tmu.h |  53 +----- 3 files
> > > > > > changed, 226 insertions(+), 174 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/thermal/samsung/Makefile
> > > > > > b/drivers/thermal/samsung/Makefile index c09d830..1e47d0d
> > > > > > 100644 --- a/drivers/thermal/samsung/Makefile
> > > > > > +++ b/drivers/thermal/samsung/Makefile
> > > > > > @@ -3,5 +3,3 @@
> > > > > >  #
> > > > > >  obj-$(CONFIG_EXYNOS_THERMAL)			+=
> > > > > > exynos_thermal.o
> > > > > > exynos_thermal-y				:=
> > > > > > exynos_tmu.o
> > > > > > -exynos_thermal-y				+=
> > > > > > exynos_tmu_data.o
> > > > > 
> > > > > Can this makefile change be part of the patch that removes
> > > > > exynos_tmu_data.c?
> > > > > 
> > > > > > -exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE)	+=
> > > > > > exynos_thermal_common.o
> > > > > 
> > > > > Can this makefile change be part of the patch that removes
> > > > > exynos_thermal_common.c?
> > > > 
> > > > Unfortunately, this code cannot be moved to the next patch, in
> > > > which I remove the files, since this causes build break of the
> > > > series.
> > > > 
> > > > The code structure as is, provides working, bisectable thermal
> > > > solution - thermal and cpu_cooling functionality is preserved
> > > > across all commits in the series.
> > > 
> > > My concern here is simply that this specific commit is leaving
> > > unused files in the tree.
> > > 
> > > One option would be to remove the files altogether in this
> > > specific commit.
> > 
> > Is is really necessary?
> > 
> > This patch itself changes around 400 LOC. Those changes __are__
> > important and in my opinion deserve their own commit.
> > 
> > When I squash following patches, which remove old exynos files, we
> > would have around 1.2K LOC in a single commit.
> > 
> > I think that current approach is far more readable. 
> 
> I agree that separating is far more readable. However, the commit
> leaves zombie files.

For a sake of simplicity, lets leave those files as zombie for one (or
at most two) commit.

> 
> > 
> > Eduardo, is there a chance for this series (the newest version is
> > v5 - which include Ablibash comments) to be included to yours -next
> > tree before v3.19 is out?
> 
> Yes, we can target this. I have sent couple of minor comments on v5.
> Despite them, there are also some parts of this series that are
> supposed to be merged via other trees. The cpufreq part seams to be
> too little and Viresh has already flagged that I can merge it as long
> it is in a separated patch. 

Indeed, this was already agreed with Viresh.

>However, most part of this series touches
> arch/arm directory and those should go via your platform tree. Is
> there a change you could either as your Exynos maintainer to queue
> the patches touching arch/arm or ask him if he is fine if I merge
> them via my tree?

I've asked Kukjin to ACK those patches, so it would be possible for you
to grab them all and push them to your tree.

Such approach allows us to keep this rework in one piece (and hence
assure no regression).

> 
> Cheers,
> 
> > 
> > > 
> > > > 
> > > > > 
> > > > > > diff --git a/drivers/thermal/samsung/exynos_tmu.c
> > > > > > b/drivers/thermal/samsung/exynos_tmu.c index
> > > > > > ae30f6a..633a9e2 100644 ---
> > > > > > a/drivers/thermal/samsung/exynos_tmu.c +++
> > > > > > b/drivers/thermal/samsung/exynos_tmu.c @@ -1,6 +1,10 @@
> > > > > >  /*
> > > > > >   * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management
> > > > > > Unit) *
> > > > > > + *  Copyright (C) 2014 Samsung Electronics
> > > > > > + *  Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> > > > > > + *  Lukasz Majewski <l.majewski@samsung.com>
> > > > > > + *
> > > > > >   *  Copyright (C) 2011 Samsung Electronics
> > > > > >   *  Donggeun Kim <dg77.kim@samsung.com>
> > > > > >   *  Amit Daniel Kachhap <amit.kachhap@linaro.org>
> > > > > > @@ -31,8 +35,8 @@
> > > > > >  #include <linux/platform_device.h>
> > > > > >  #include <linux/regulator/consumer.h>
> > > > > >  
> > > > > > -#include "exynos_thermal_common.h"
> > > > > >  #include "exynos_tmu.h"
> > > > > > +#include "../thermal_core.h"
> > > > > >  
> > > > > >  /* Exynos generic registers */
> > > > > >  #define EXYNOS_TMU_REG_TRIMINFO		0x0
> > > > > > @@ -115,6 +119,7 @@
> > > > > >  #define EXYNOS5440_TMU_TH_RISE4_SHIFT		24
> > > > > >  #define EXYNOS5440_EFUSE_SWAP_OFFSET		8
> > > > > >  
> > > > > > +#define MCELSIUS	1000
> > > > > >  /**
> > > > > >   * struct exynos_tmu_data : A structure to hold the private
> > > > > > data of the TMU driver
> > > > > > @@ -150,7 +155,8 @@ struct exynos_tmu_data {
> > > > > >  	struct clk *clk, *clk_sec;
> > > > > >  	u8 temp_error1, temp_error2;
> > > > > >  	struct regulator *regulator;
> > > > > > -	struct thermal_sensor_conf *reg_conf;
> > > > > > +	struct thermal_zone_device *tzd;
> > > > > > +
> > > > > >  	int (*tmu_initialize)(struct platform_device
> > > > > > *pdev); void (*tmu_control)(struct platform_device *pdev,
> > > > > > bool on); int (*tmu_read)(struct exynos_tmu_data *data);
> > > > > > @@ -159,6 +165,33 @@ struct exynos_tmu_data {
> > > > > >  	void (*tmu_clear_irqs)(struct exynos_tmu_data
> > > > > > *data); };
> > > > > >  
> > > > > > +static void exynos_report_trigger(struct exynos_tmu_data
> > > > > > *p) +{
> > > > > > +	char data[10], *envp[] = { data, NULL };
> > > > > > +	struct thermal_zone_device *tz = p->tzd;
> > > > > > +	unsigned long temp;
> > > > > > +	unsigned int i;
> > > > > > +
> > > > > > +	if (!p) {
> > > > > > +		pr_err("Wrong temperature configuration
> > > > > > data\n");
> > > > > > +		return;
> > > > > > +	}
> > > > > > +
> > > > > > +	thermal_zone_device_update(tz);
> > > > > > +
> > > > > > +	mutex_lock(&tz->lock);
> > > > > > +	/* Find the level for which trip happened */
> > > > > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > > > > +		tz->ops->get_trip_temp(tz, i, &temp);
> > > > > > +		if (tz->last_temperature < temp)
> > > > > > +			break;
> > > > > > +	}
> > > > > > +
> > > > > > +	snprintf(data, sizeof(data), "%u", i);
> > > > > > +	kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE,
> > > > > > envp);
> > > > > > +	mutex_unlock(&tz->lock);
> > > > > > +}
> > > > > > +
> > > > > >  /*
> > > > > >   * TMU treats temperature as a mapped temperature code.
> > > > > >   * The temperature is converted differently depending on
> > > > > > the calibration type. @@ -234,14 +267,25 @@ static void
> > > > > > sanitize_temp_error(struct exynos_tmu_data *data, u32
> > > > > > trim_info) static u32 get_th_reg(struct exynos_tmu_data
> > > > > > *data, u32 threshold, bool falling) {
> > > > > > -	struct exynos_tmu_platform_data *pdata =
> > > > > > data->pdata;
> > > > > > +	struct thermal_zone_device *tz = data->tzd;
> > > > > > +	const struct thermal_trip * const trips =
> > > > > > +		of_thermal_get_trip_points(tz);
> > > > > > +	unsigned long temp;
> > > > > >  	int i;
> > > > > >  
> > > > > > -	for (i = 0; i < pdata->non_hw_trigger_levels; i++)
> > > > > > {
> > > > > > -		u8 temp = pdata->trigger_levels[i];
> > > > > > +	if (!trips) {
> > > > > > +		pr_err("%s: Cannot get trip points from
> > > > > > of-thermal.c!\n",
> > > > > > +		       __func__);
> > > > > > +		return 0;
> > > > > > +	}
> > > > > > +
> > > > > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > > > > +		if (trips[i].type == THERMAL_TRIP_CRITICAL)
> > > > > > +			continue;
> > > > > >  
> > > > > > +		temp = trips[i].temperature / MCELSIUS;
> > > > > >  		if (falling)
> > > > > > -			temp -= pdata->threshold_falling;
> > > > > > +			temp -= (trips[i].hysteresis /
> > > > > > MCELSIUS); else
> > > > > >  			threshold &= ~(0xff << 8 * i);
> > > > > >  
> > > > > > @@ -305,9 +349,19 @@ static void exynos_tmu_control(struct
> > > > > > platform_device *pdev, bool on) static int
> > > > > > exynos4210_tmu_initialize(struct platform_device *pdev) {
> > > > > >  	struct exynos_tmu_data *data =
> > > > > > platform_get_drvdata(pdev);
> > > > > > -	struct exynos_tmu_platform_data *pdata =
> > > > > > data->pdata;
> > > > > > -	unsigned int status;
> > > > > > +	struct thermal_zone_device *tz = data->tzd;
> > > > > > +	const struct thermal_trip * const trips =
> > > > > > +		of_thermal_get_trip_points(tz);
> > > > > >  	int ret = 0, threshold_code, i;
> > > > > > +	unsigned long reference, temp;
> > > > > > +	unsigned int status;
> > > > > > +
> > > > > > +	if (!trips) {
> > > > > > +		pr_err("%s: Cannot get trip points from
> > > > > > of-thermal.c!\n",
> > > > > > +		       __func__);
> > > > > > +		ret = -ENODEV;
> > > > > > +		goto out;
> > > > > > +	}
> > > > > >  
> > > > > >  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> > > > > >  	if (!status) {
> > > > > > @@ -318,12 +372,19 @@ static int
> > > > > > exynos4210_tmu_initialize(struct platform_device *pdev)
> > > > > > sanitize_temp_error(data, readl(data->base +
> > > > > > EXYNOS_TMU_REG_TRIMINFO)); /* Write temperature code for
> > > > > > threshold */
> > > > > > -	threshold_code = temp_to_code(data,
> > > > > > pdata->threshold);
> > > > > > +	reference = trips[0].temperature / MCELSIUS;
> > > > > > +	threshold_code = temp_to_code(data, reference);
> > > > > > +	if (threshold_code < 0) {
> > > > > > +		ret = threshold_code;
> > > > > > +		goto out;
> > > > > > +	}
> > > > > >  	writeb(threshold_code, data->base +
> > > > > > EXYNOS4210_TMU_REG_THRESHOLD_TEMP); 
> > > > > > -	for (i = 0; i < pdata->non_hw_trigger_levels; i++)
> > > > > > -		writeb(pdata->trigger_levels[i],
> > > > > > data->base +
> > > > > > +	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
> > > > > > +		temp = trips[i].temperature / MCELSIUS;
> > > > > > +		writeb(temp - reference, data->base +
> > > > > >  		       EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i
> > > > > > * 4);
> > > > > > +	}
> > > > > >  
> > > > > >  	data->tmu_clear_irqs(data);
> > > > > >  out:
> > > > > > @@ -333,9 +394,11 @@ out:
> > > > > >  static int exynos4412_tmu_initialize(struct platform_device
> > > > > > *pdev) {
> > > > > >  	struct exynos_tmu_data *data =
> > > > > > platform_get_drvdata(pdev);
> > > > > > -	struct exynos_tmu_platform_data *pdata =
> > > > > > data->pdata;
> > > > > > +	const struct thermal_trip * const trips =
> > > > > > +		of_thermal_get_trip_points(data->tzd);
> > > > > >  	unsigned int status, trim_info, con, ctrl,
> > > > > > rising_threshold; int ret = 0, threshold_code, i;
> > > > > > +	unsigned long crit_temp = 0;
> > > > > >  
> > > > > >  	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> > > > > >  	if (!status) {
> > > > > > @@ -373,17 +436,29 @@ static int
> > > > > > exynos4412_tmu_initialize(struct platform_device *pdev)
> > > > > > data->tmu_clear_irqs(data); 
> > > > > >  	/* if last threshold limit is also present */
> > > > > > -	i = pdata->max_trigger_level - 1;
> > > > > > -	if (pdata->trigger_levels[i] &&
> > > > > > pdata->trigger_type[i] == HW_TRIP) {
> > > > > > -		threshold_code = temp_to_code(data,
> > > > > > pdata->trigger_levels[i]);
> > > > > > -		/* 1-4 level to be assigned in th0 reg */
> > > > > > -		rising_threshold &= ~(0xff << 8 * i);
> > > > > > -		rising_threshold |= threshold_code << 8 *
> > > > > > i;
> > > > > > -		writel(rising_threshold, data->base +
> > > > > > EXYNOS_THD_TEMP_RISE);
> > > > > > -		con = readl(data->base +
> > > > > > EXYNOS_TMU_REG_CONTROL);
> > > > > > -		con |= (1 <<
> > > > > > EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > > > > > -		writel(con, data->base +
> > > > > > EXYNOS_TMU_REG_CONTROL);
> > > > > > +	for (i = 0; i < of_thermal_get_ntrips(data->tzd);
> > > > > > i++) {
> > > > > > +		if (trips[i].type ==
> > > > > > THERMAL_TRIP_CRITICAL) {
> > > > > > +			crit_temp = trips[i].temperature;
> > > > > > +			break;
> > > > > > +		}
> > > > > >  	}
> > > > > > +
> > > > > > +	if (i == of_thermal_get_ntrips(data->tzd)) {
> > > > > > +		pr_err("%s: No CRITICAL trip point defined
> > > > > > at of-thermal.c!\n",
> > > > > > +		       __func__);
> > > > > > +		ret = -EINVAL;
> > > > > > +		goto out;
> > > > > > +	}
> > > > > > +
> > > > > > +	threshold_code = temp_to_code(data, crit_temp /
> > > > > > MCELSIUS);
> > > > > > +	/* 1-4 level to be assigned in th0 reg */
> > > > > > +	rising_threshold &= ~(0xff << 8 * i);
> > > > > > +	rising_threshold |= threshold_code << 8 * i;
> > > > > > +	writel(rising_threshold, data->base +
> > > > > > EXYNOS_THD_TEMP_RISE);
> > > > > > +	con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
> > > > > > +	con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
> > > > > > +	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> > > > > > +
> > > > > >  out:
> > > > > >  	return ret;
> > > > > >  }
> > > > > > @@ -391,9 +466,9 @@ out:
> > > > > >  static int exynos5440_tmu_initialize(struct platform_device
> > > > > > *pdev) {
> > > > > >  	struct exynos_tmu_data *data =
> > > > > > platform_get_drvdata(pdev);
> > > > > > -	struct exynos_tmu_platform_data *pdata =
> > > > > > data->pdata; unsigned int trim_info = 0, con,
> > > > > > rising_threshold;
> > > > > > -	int ret = 0, threshold_code, i;
> > > > > > +	int ret = 0, threshold_code;
> > > > > > +	unsigned long crit_temp = 0;
> > > > > >  
> > > > > >  	/*
> > > > > >  	 * For exynos5440 soc triminfo value is swapped
> > > > > > between TMU0 and @@ -422,9 +497,8 @@ static int
> > > > > > exynos5440_tmu_initialize(struct platform_device *pdev)
> > > > > > data->tmu_clear_irqs(data); 
> > > > > >  	/* if last threshold limit is also present */
> > > > > > -	i = pdata->max_trigger_level - 1;
> > > > > > -	if (pdata->trigger_levels[i] &&
> > > > > > pdata->trigger_type[i] == HW_TRIP) {
> > > > > > -		threshold_code = temp_to_code(data,
> > > > > > pdata->trigger_levels[i]);
> > > > > > +	if (!data->tzd->ops->get_crit_temp(data->tzd,
> > > > > > &crit_temp)) {
> > > > > > +		threshold_code = temp_to_code(data,
> > > > > > crit_temp / MCELSIUS); /* 5th level to be assigned in th2
> > > > > > reg */ rising_threshold =
> > > > > >  			threshold_code <<
> > > > > > EXYNOS5440_TMU_TH_RISE4_SHIFT; @@ -442,7 +516,7 @@ static
> > > > > > int exynos5440_tmu_initialize(struct platform_device *pdev)
> > > > > > static void exynos4210_tmu_control(struct platform_device
> > > > > > *pdev, bool on) { struct exynos_tmu_data *data =
> > > > > > platform_get_drvdata(pdev);
> > > > > > -	struct exynos_tmu_platform_data *pdata =
> > > > > > data->pdata;
> > > > > > +	struct thermal_zone_device *tz = data->tzd;
> > > > > >  	unsigned int con, interrupt_en;
> > > > > >  
> > > > > >  	con = get_con_reg(data, readl(data->base +
> > > > > > EXYNOS_TMU_REG_CONTROL)); @@ -450,10 +524,15 @@ static void
> > > > > > exynos4210_tmu_control(struct platform_device *pdev, bool
> > > > > > on) if (on) { con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > > > > >  		interrupt_en =
> > > > > > -			pdata->trigger_enable[3] <<
> > > > > > EXYNOS_TMU_INTEN_RISE3_SHIFT |
> > > > > > -			pdata->trigger_enable[2] <<
> > > > > > EXYNOS_TMU_INTEN_RISE2_SHIFT |
> > > > > > -			pdata->trigger_enable[1] <<
> > > > > > EXYNOS_TMU_INTEN_RISE1_SHIFT |
> > > > > > -			pdata->trigger_enable[0] <<
> > > > > > EXYNOS_TMU_INTEN_RISE0_SHIFT;
> > > > > > +			(of_thermal_is_trip_valid(tz, 3)
> > > > > > +			 << EXYNOS_TMU_INTEN_RISE3_SHIFT) |
> > > > > > +			(of_thermal_is_trip_valid(tz, 2)
> > > > > > +			 << EXYNOS_TMU_INTEN_RISE2_SHIFT) |
> > > > > > +			(of_thermal_is_trip_valid(tz, 1)
> > > > > > +			 << EXYNOS_TMU_INTEN_RISE1_SHIFT) |
> > > > > > +			(of_thermal_is_trip_valid(tz, 0)
> > > > > > +			 << EXYNOS_TMU_INTEN_RISE0_SHIFT);
> > > > > > +
> > > > > >  		if (data->soc != SOC_ARCH_EXYNOS4210)
> > > > > >  			interrupt_en |=
> > > > > >  				interrupt_en <<
> > > > > > EXYNOS_TMU_INTEN_FALL0_SHIFT; @@ -468,7 +547,7 @@ static
> > > > > > void exynos4210_tmu_control(struct platform_device *pdev,
> > > > > > bool on) static void exynos5440_tmu_control(struct
> > > > > > platform_device *pdev, bool on) { struct exynos_tmu_data
> > > > > > *data = platform_get_drvdata(pdev);
> > > > > > -	struct exynos_tmu_platform_data *pdata =
> > > > > > data->pdata;
> > > > > > +	struct thermal_zone_device *tz = data->tzd;
> > > > > >  	unsigned int con, interrupt_en;
> > > > > >  
> > > > > >  	con = get_con_reg(data, readl(data->base +
> > > > > > EXYNOS5440_TMU_S0_7_CTRL)); @@ -476,11 +555,16 @@ static
> > > > > > void exynos5440_tmu_control(struct platform_device *pdev,
> > > > > > bool on) if (on) { con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > > > > >  		interrupt_en =
> > > > > > -			pdata->trigger_enable[3] <<
> > > > > > EXYNOS5440_TMU_INTEN_RISE3_SHIFT |
> > > > > > -			pdata->trigger_enable[2] <<
> > > > > > EXYNOS5440_TMU_INTEN_RISE2_SHIFT |
> > > > > > -			pdata->trigger_enable[1] <<
> > > > > > EXYNOS5440_TMU_INTEN_RISE1_SHIFT |
> > > > > > -			pdata->trigger_enable[0] <<
> > > > > > EXYNOS5440_TMU_INTEN_RISE0_SHIFT;
> > > > > > -		interrupt_en |= interrupt_en <<
> > > > > > EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
> > > > > > +			(of_thermal_is_trip_valid(tz, 3)
> > > > > > +			 <<
> > > > > > EXYNOS5440_TMU_INTEN_RISE3_SHIFT) |
> > > > > > +			(of_thermal_is_trip_valid(tz, 2)
> > > > > > +			 <<
> > > > > > EXYNOS5440_TMU_INTEN_RISE2_SHIFT) |
> > > > > > +			(of_thermal_is_trip_valid(tz, 1)
> > > > > > +			 <<
> > > > > > EXYNOS5440_TMU_INTEN_RISE1_SHIFT) |
> > > > > > +			(of_thermal_is_trip_valid(tz, 0)
> > > > > > +			 <<
> > > > > > EXYNOS5440_TMU_INTEN_RISE0_SHIFT);
> > > > > > +		interrupt_en |=
> > > > > > +			interrupt_en <<
> > > > > > EXYNOS5440_TMU_INTEN_FALL0_SHIFT; } else {
> > > > > >  		con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
> > > > > >  		interrupt_en = 0; /* Disable all
> > > > > > interrupts */ @@ -489,19 +573,22 @@ static void
> > > > > > exynos5440_tmu_control(struct platform_device *pdev, bool
> > > > > > on) writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL); }
> > > > > >  
> > > > > > -static int exynos_tmu_read(struct exynos_tmu_data *data)
> > > > > > +int exynos_get_temp(void *p, long *temp)
> > > > > >  {
> > > > > > -	int ret;
> > > > > > +	struct exynos_tmu_data *data = p;
> > > > > > +
> > > > > > +	if (!data)
> > > > > > +		return -EINVAL;
> > > > > >  
> > > > > >  	mutex_lock(&data->lock);
> > > > > >  	clk_enable(data->clk);
> > > > > > -	ret = data->tmu_read(data);
> > > > > > -	if (ret >= 0)
> > > > > > -		ret = code_to_temp(data, ret);
> > > > > > +
> > > > > > +	*temp = code_to_temp(data, data->tmu_read(data)) *
> > > > > > MCELSIUS; +
> > > > > >  	clk_disable(data->clk);
> > > > > >  	mutex_unlock(&data->lock);
> > > > > >  
> > > > > > -	return ret;
> > > > > > +	return 0;
> > > > > >  }
> > > > > >  
> > > > > >  #ifdef CONFIG_THERMAL_EMULATION
> > > > > > @@ -613,7 +700,7 @@ static void exynos_tmu_work(struct
> > > > > > work_struct *work) if (!IS_ERR(data->clk_sec))
> > > > > >  		clk_disable(data->clk_sec);
> > > > > >  
> > > > > > -	exynos_report_trigger(data->reg_conf);
> > > > > > +	exynos_report_trigger(data);
> > > > > >  	mutex_lock(&data->lock);
> > > > > >  	clk_enable(data->clk);
> > > > > >  
> > > > > > @@ -673,55 +760,89 @@ static irqreturn_t exynos_tmu_irq(int
> > > > > > irq, void *id) static const struct of_device_id
> > > > > > exynos_tmu_match[] = { {
> > > > > >  		.compatible = "samsung,exynos3250-tmu",
> > > > > > -		.data = &exynos3250_default_tmu_data,
> > > > > >  	},
> > > > > >  	{
> > > > > >  		.compatible = "samsung,exynos4210-tmu",
> > > > > > -		.data = &exynos4210_default_tmu_data,
> > > > > >  	},
> > > > > >  	{
> > > > > >  		.compatible = "samsung,exynos4412-tmu",
> > > > > > -		.data = &exynos4412_default_tmu_data,
> > > > > >  	},
> > > > > >  	{
> > > > > >  		.compatible = "samsung,exynos5250-tmu",
> > > > > > -		.data = &exynos5250_default_tmu_data,
> > > > > >  	},
> > > > > >  	{
> > > > > >  		.compatible = "samsung,exynos5260-tmu",
> > > > > > -		.data = &exynos5260_default_tmu_data,
> > > > > >  	},
> > > > > >  	{
> > > > > >  		.compatible = "samsung,exynos5420-tmu",
> > > > > > -		.data = &exynos5420_default_tmu_data,
> > > > > >  	},
> > > > > >  	{
> > > > > >  		.compatible =
> > > > > > "samsung,exynos5420-tmu-ext-triminfo",
> > > > > > -		.data = &exynos5420_default_tmu_data,
> > > > > >  	},
> > > > > >  	{
> > > > > >  		.compatible = "samsung,exynos5440-tmu",
> > > > > > -		.data = &exynos5440_default_tmu_data,
> > > > > >  	},
> > > > > >  	{},
> > > > > >  };
> > > > > >  MODULE_DEVICE_TABLE(of, exynos_tmu_match);
> > > > > >  
> > > > > > -static inline struct  exynos_tmu_platform_data
> > > > > > *exynos_get_driver_data(
> > > > > > -			struct platform_device *pdev, int
> > > > > > id) +static int exynos_of_get_soc_type(struct device_node
> > > > > > *np) {
> > > > > > -	struct  exynos_tmu_init_data *data_table;
> > > > > > -	struct exynos_tmu_platform_data *tmu_data;
> > > > > > -	const struct of_device_id *match;
> > > > > > +	if (of_device_is_compatible(np,
> > > > > > "samsung,exynos3250-tmu"))
> > > > > > +		return SOC_ARCH_EXYNOS3250;
> > > > > > +	else if (of_device_is_compatible(np,
> > > > > > "samsung,exynos4210-tmu"))
> > > > > > +		return SOC_ARCH_EXYNOS4210;
> > > > > > +	else if (of_device_is_compatible(np,
> > > > > > "samsung,exynos4412-tmu"))
> > > > > > +		return SOC_ARCH_EXYNOS4412;
> > > > > > +	else if (of_device_is_compatible(np,
> > > > > > "samsung,exynos5250-tmu"))
> > > > > > +		return SOC_ARCH_EXYNOS5250;
> > > > > > +	else if (of_device_is_compatible(np,
> > > > > > "samsung,exynos5260-tmu"))
> > > > > > +		return SOC_ARCH_EXYNOS5260;
> > > > > > +	else if (of_device_is_compatible(np,
> > > > > > "samsung,exynos5420-tmu"))
> > > > > > +		return SOC_ARCH_EXYNOS5420;
> > > > > > +	else if (of_device_is_compatible(np,
> > > > > > +
> > > > > > "samsung,exynos5420-tmu-ext-triminfo"))
> > > > > > +		return SOC_ARCH_EXYNOS5420_TRIMINFO;
> > > > > > +	else if (of_device_is_compatible(np,
> > > > > > "samsung,exynos5440-tmu"))
> > > > > > +		return SOC_ARCH_EXYNOS5440;
> > > > > > +
> > > > > > +	return -EINVAL;
> > > > > > +}
> > > > > >  
> > > > > > -	match = of_match_node(exynos_tmu_match,
> > > > > > pdev->dev.of_node);
> > > > > > -	if (!match)
> > > > > > -		return NULL;
> > > > > > -	data_table = (struct exynos_tmu_init_data *)
> > > > > > match->data;
> > > > > > -	if (!data_table || id >= data_table->tmu_count)
> > > > > > -		return NULL;
> > > > > > -	tmu_data = data_table->tmu_data;
> > > > > > -	return (struct exynos_tmu_platform_data *)
> > > > > > (tmu_data + id); +static int exynos_of_sensor_conf(struct
> > > > > > device_node *np,
> > > > > > +				 struct
> > > > > > exynos_tmu_platform_data *pdata) +{
> > > > > > +	u32 value;
> > > > > > +	int ret;
> > > > > > +
> > > > > > +	of_node_get(np);
> > > > > > +
> > > > > > +	ret = of_property_read_u32(np, "samsung,tmu_gain",
> > > > > > &value);
> > > > > > +	pdata->gain = (u8) value;
> > > > > > +	of_property_read_u32(np,
> > > > > > "samsung,tmu_reference_voltage", &value);
> > > > > > +	pdata->reference_voltage = (u8) value;
> > > > > > +	of_property_read_u32(np,
> > > > > > "samsung,tmu_noise_cancel_mode", &value);
> > > > > > +	pdata->noise_cancel_mode = (u8) value;
> > > > > > +
> > > > > > +	of_property_read_u32(np, "samsung,tmu_efuse_value",
> > > > > > +			     &pdata->efuse_value);
> > > > > > +	of_property_read_u32(np,
> > > > > > "samsung,tmu_min_efuse_value",
> > > > > > +			     &pdata->min_efuse_value);
> > > > > > +	of_property_read_u32(np,
> > > > > > "samsung,tmu_max_efuse_value",
> > > > > > +			     &pdata->max_efuse_value);
> > > > > > +
> > > > > > +	of_property_read_u32(np,
> > > > > > "samsung,tmu_first_point_trim", &value);
> > > > > > +	pdata->first_point_trim = (u8) value;
> > > > > > +	of_property_read_u32(np,
> > > > > > "samsung,tmu_second_point_trim", &value);
> > > > > > +	pdata->second_point_trim = (u8) value;
> > > > > > +	of_property_read_u32(np,
> > > > > > "samsung,tmu_default_temp_offset", &value);
> > > > > > +	pdata->default_temp_offset = (u8) value;
> > > > > > +
> > > > > > +	of_property_read_u32(np, "samsung,tmu_cal_type",
> > > > > > &pdata->cal_type);
> > > > > > +	of_property_read_u32(np, "samsung,tmu_cal_mode",
> > > > > > &pdata->cal_mode); +
> > > > > > +	of_node_put(np);
> > > > > > +	return 0;
> > > > > >  }
> > > > > >  
> > > > > >  static int exynos_map_dt_data(struct platform_device *pdev)
> > > > > > @@ -771,14 +892,15 @@ static int exynos_map_dt_data(struct
> > > > > > platform_device *pdev) return -EADDRNOTAVAIL;
> > > > > >  	}
> > > > > >  
> > > > > > -	pdata = exynos_get_driver_data(pdev, data->id);
> > > > > > -	if (!pdata) {
> > > > > > -		dev_err(&pdev->dev, "No platform init data
> > > > > > supplied.\n");
> > > > > > -		return -ENODEV;
> > > > > > -	}
> > > > > > +	pdata = devm_kzalloc(&pdev->dev,
> > > > > > +			     sizeof(struct
> > > > > > exynos_tmu_platform_data),
> > > > > > +			     GFP_KERNEL);
> > > > > > +	if (!pdata)
> > > > > > +		return -ENOMEM;
> > > > > >  
> > > > > > +	exynos_of_sensor_conf(pdev->dev.of_node, pdata);
> > > > > >  	data->pdata = pdata;
> > > > > > -	data->soc = pdata->type;
> > > > > > +	data->soc =
> > > > > > exynos_of_get_soc_type(pdev->dev.of_node); 
> > > > > >  	switch (data->soc) {
> > > > > >  	case SOC_ARCH_EXYNOS4210:
> > > > > > @@ -834,12 +956,16 @@ static int exynos_map_dt_data(struct
> > > > > > platform_device *pdev) return 0;
> > > > > >  }
> > > > > >  
> > > > > > +static struct thermal_zone_of_device_ops exynos_sensor_ops
> > > > > > = {
> > > > > > +	.get_temp = exynos_get_temp,
> > > > > > +	.set_emul_temp = exynos_tmu_set_emulation,
> > > > > > +};
> > > > > > +
> > > > > >  static int exynos_tmu_probe(struct platform_device *pdev)
> > > > > >  {
> > > > > > -	struct exynos_tmu_data *data;
> > > > > >  	struct exynos_tmu_platform_data *pdata;
> > > > > > -	struct thermal_sensor_conf *sensor_conf;
> > > > > > -	int ret, i;
> > > > > > +	struct exynos_tmu_data *data;
> > > > > > +	int ret;
> > > > > >  
> > > > > >  	data = devm_kzalloc(&pdev->dev, sizeof(struct
> > > > > > exynos_tmu_data), GFP_KERNEL);
> > > > > > @@ -849,9 +975,15 @@ static int exynos_tmu_probe(struct
> > > > > > platform_device *pdev) platform_set_drvdata(pdev, data);
> > > > > >  	mutex_init(&data->lock);
> > > > > >  
> > > > > > +	data->tzd =
> > > > > > thermal_zone_of_sensor_register(&pdev->dev, 0, data,
> > > > > > +
> > > > > > &exynos_sensor_ops);
> > > > > > +	if (IS_ERR(data->tzd)) {
> > > > > > +		pr_err("thermal: tz: %p ERROR\n",
> > > > > > data->tzd);
> > > > > > +		return PTR_ERR(data->tzd);
> > > > > > +	}
> > > > > >  	ret = exynos_map_dt_data(pdev);
> > > > > >  	if (ret)
> > > > > > -		return ret;
> > > > > > +		goto err_sensor;
> > > > > >  
> > > > > >  	pdata = data->pdata;
> > > > > >  
> > > > > > @@ -860,20 +992,22 @@ static int exynos_tmu_probe(struct
> > > > > > platform_device *pdev) data->clk = devm_clk_get(&pdev->dev,
> > > > > > "tmu_apbif"); if (IS_ERR(data->clk)) {
> > > > > >  		dev_err(&pdev->dev, "Failed to get
> > > > > > clock\n");
> > > > > > -		return  PTR_ERR(data->clk);
> > > > > > +		ret = PTR_ERR(data->clk);
> > > > > > +		goto err_sensor;
> > > > > >  	}
> > > > > >  
> > > > > >  	data->clk_sec = devm_clk_get(&pdev->dev,
> > > > > > "tmu_triminfo_apbif"); if (IS_ERR(data->clk_sec)) {
> > > > > >  		if (data->soc ==
> > > > > > SOC_ARCH_EXYNOS5420_TRIMINFO) { dev_err(&pdev->dev, "Failed
> > > > > > to get triminfo clock\n");
> > > > > > -			return PTR_ERR(data->clk_sec);
> > > > > > +			ret = PTR_ERR(data->clk_sec);
> > > > > > +			goto err_sensor;
> > > > > >  		}
> > > > > >  	} else {
> > > > > >  		ret = clk_prepare(data->clk_sec);
> > > > > >  		if (ret) {
> > > > > >  			dev_err(&pdev->dev, "Failed to get
> > > > > > clock\n");
> > > > > > -			return ret;
> > > > > > +			goto err_sensor;
> > > > > >  		}
> > > > > >  	}
> > > > > >  
> > > > > > @@ -889,45 +1023,6 @@ static int exynos_tmu_probe(struct
> > > > > > platform_device *pdev) goto err_clk;
> > > > > >  	}
> > > > > >  
> > > > > > -	exynos_tmu_control(pdev, true);
> > > > > > -
> > > > > > -	/* Allocate a structure to register with the exynos
> > > > > > core thermal */
> > > > > > -	sensor_conf = devm_kzalloc(&pdev->dev,
> > > > > > -				sizeof(struct
> > > > > > thermal_sensor_conf), GFP_KERNEL);
> > > > > > -	if (!sensor_conf) {
> > > > > > -		ret = -ENOMEM;
> > > > > > -		goto err_clk;
> > > > > > -	}
> > > > > > -	sprintf(sensor_conf->name, "therm_zone%d",
> > > > > > data->id);
> > > > > > -	sensor_conf->read_temperature = (int (*)(void
> > > > > > *))exynos_tmu_read;
> > > > > > -	sensor_conf->write_emul_temp =
> > > > > > -		(int (*)(void *, unsigned
> > > > > > long))exynos_tmu_set_emulation;
> > > > > > -	sensor_conf->driver_data = data;
> > > > > > -	sensor_conf->trip_data.trip_count =
> > > > > > pdata->trigger_enable[0] +
> > > > > > -			pdata->trigger_enable[1] +
> > > > > > pdata->trigger_enable[2]+
> > > > > > -			pdata->trigger_enable[3];
> > > > > > -
> > > > > > -	for (i = 0; i < sensor_conf->trip_data.trip_count;
> > > > > > i++) {
> > > > > > -		sensor_conf->trip_data.trip_val[i] =
> > > > > > -			pdata->threshold +
> > > > > > pdata->trigger_levels[i];
> > > > > > -		sensor_conf->trip_data.trip_type[i] =
> > > > > > -
> > > > > > pdata->trigger_type[i];
> > > > > > -	}
> > > > > > -
> > > > > > -	sensor_conf->trip_data.trigger_falling =
> > > > > > pdata->threshold_falling; -
> > > > > > -	sensor_conf->dev = &pdev->dev;
> > > > > > -	/* Register the sensor with thermal management
> > > > > > interface */
> > > > > > -	ret = exynos_register_thermal(sensor_conf);
> > > > > > -	if (ret) {
> > > > > > -		if (ret != -EPROBE_DEFER)
> > > > > > -			dev_err(&pdev->dev,
> > > > > > -				"Failed to register thermal
> > > > > > interface: %d\n",
> > > > > > -				ret);
> > > > > > -		goto err_clk;
> > > > > > -	}
> > > > > > -	data->reg_conf = sensor_conf;
> > > > > > -
> > > > > >  	ret = devm_request_irq(&pdev->dev, data->irq,
> > > > > > exynos_tmu_irq, IRQF_TRIGGER_RISING | IRQF_SHARED,
> > > > > > dev_name(&pdev->dev), data); if (ret) {
> > > > > > @@ -935,21 +1030,31 @@ static int exynos_tmu_probe(struct
> > > > > > platform_device *pdev) goto err_clk;
> > > > > >  	}
> > > > > >  
> > > > > > +	ret = exynos_tmu_initialize(pdev);
> > > > > > +	if (ret) {
> > > > > > +		dev_err(&pdev->dev, "Failed to initialize
> > > > > > TMU\n");
> > > > > > +		goto err_clk;
> > > > > > +	}
> > > > > > +	exynos_tmu_control(pdev, true);
> > > > > >  	return 0;
> > > > > > +
> > > > > >  err_clk:
> > > > > >  	clk_unprepare(data->clk);
> > > > > >  err_clk_sec:
> > > > > >  	if (!IS_ERR(data->clk_sec))
> > > > > >  		clk_unprepare(data->clk_sec);
> > > > > > +err_sensor:
> > > > > > +	thermal_zone_of_sensor_unregister(&pdev->dev,
> > > > > > data->tzd); +
> > > > > >  	return ret;
> > > > > >  }
> > > > > >  
> > > > > >  static int exynos_tmu_remove(struct platform_device *pdev)
> > > > > >  {
> > > > > >  	struct exynos_tmu_data *data =
> > > > > > platform_get_drvdata(pdev);
> > > > > > +	struct thermal_zone_device *tzd = data->tzd;
> > > > > >  
> > > > > > -	exynos_unregister_thermal(data->reg_conf);
> > > > > > -
> > > > > > +	thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
> > > > > >  	exynos_tmu_control(pdev, false);
> > > > > >  
> > > > > >  	clk_unprepare(data->clk);
> > > > > > diff --git a/drivers/thermal/samsung/exynos_tmu.h
> > > > > > b/drivers/thermal/samsung/exynos_tmu.h index
> > > > > > 627dec9..d876d4c 100644 ---
> > > > > > a/drivers/thermal/samsung/exynos_tmu.h +++
> > > > > > b/drivers/thermal/samsung/exynos_tmu.h @@ -23,8 +23,7 @@
> > > > > >  #ifndef _EXYNOS_TMU_H
> > > > > >  #define _EXYNOS_TMU_H
> > > > > >  #include <linux/cpu_cooling.h>
> > > > > > -
> > > > > > -#include "exynos_thermal_common.h"
> > > > > > +#include <dt-bindings/thermal/thermal_exynos.h>
> > > > > >  
> > > > > >  enum soc_type {
> > > > > >  	SOC_ARCH_EXYNOS3250 = 1,
> > > > > > @@ -36,38 +35,9 @@ enum soc_type {
> > > > > >  	SOC_ARCH_EXYNOS5420_TRIMINFO,
> > > > > >  	SOC_ARCH_EXYNOS5440,
> > > > > >  };
> > > > > > -#include <dt-bindings/thermal/thermal_exynos.h>
> > > > > >  
> > > > > >  /**
> > > > > >   * struct exynos_tmu_platform_data
> > > > > > - * @threshold: basic temperature for generating interrupt
> > > > > > - *	       25 <= threshold <= 125 [unit: degree
> > > > > > Celsius]
> > > > > > - * @threshold_falling: differntial value for setting
> > > > > > threshold
> > > > > > - *		       of temperature falling interrupt.
> > > > > > - * @trigger_levels: array for each interrupt levels
> > > > > > - *	[unit: degree Celsius]
> > > > > > - *	0: temperature for trigger_level0 interrupt
> > > > > > - *	   condition for trigger_level0 interrupt:
> > > > > > - *		current temperature > threshold +
> > > > > > trigger_levels[0]
> > > > > > - *	1: temperature for trigger_level1 interrupt
> > > > > > - *	   condition for trigger_level1 interrupt:
> > > > > > - *		current temperature > threshold +
> > > > > > trigger_levels[1]
> > > > > > - *	2: temperature for trigger_level2 interrupt
> > > > > > - *	   condition for trigger_level2 interrupt:
> > > > > > - *		current temperature > threshold +
> > > > > > trigger_levels[2]
> > > > > > - *	3: temperature for trigger_level3 interrupt
> > > > > > - *	   condition for trigger_level3 interrupt:
> > > > > > - *		current temperature > threshold +
> > > > > > trigger_levels[3]
> > > > > > - * @trigger_type: defines the type of trigger. Possible
> > > > > > values are,
> > > > > > - *	THROTTLE_ACTIVE trigger type
> > > > > > - *	THROTTLE_PASSIVE trigger type
> > > > > > - *	SW_TRIP trigger type
> > > > > > - *	HW_TRIP
> > > > > > - * @trigger_enable[]: array to denote which trigger levels
> > > > > > are enabled.
> > > > > > - *	1 = enable trigger_level[] interrupt,
> > > > > > - *	0 = disable trigger_level[] interrupt
> > > > > > - * @max_trigger_level: max trigger level supported by the
> > > > > > TMU
> > > > > > - * @non_hw_trigger_levels: number of defined non-hardware
> > > > > > trigger levels
> > > > > >   * @gain: gain of amplifier in the positive-TC generator
> > > > > > block
> > > > > >   *	0 < gain <= 15
> > > > > >   * @reference_voltage: reference voltage of amplifier
> > > > > > @@ -79,21 +49,12 @@ enum soc_type {
> > > > > >   * @efuse_value: platform defined fuse value
> > > > > >   * @min_efuse_value: minimum valid trimming data
> > > > > >   * @max_efuse_value: maximum valid trimming data
> > > > > > - * @first_point_trim: temp value of the first point
> > > > > > trimming
> > > > > > - * @second_point_trim: temp value of the second point
> > > > > > trimming
> > > > > >   * @default_temp_offset: default temperature offset in
> > > > > > case of no trimming
> > > > > >   * @cal_type: calibration type for temperature
> > > > > >   *
> > > > > >   * This structure is required for configuration of
> > > > > > exynos_tmu driver. */
> > > > > >  struct exynos_tmu_platform_data {
> > > > > > -	u8 threshold;
> > > > > > -	u8 threshold_falling;
> > > > > > -	u8 trigger_levels[MAX_TRIP_COUNT];
> > > > > > -	enum trigger_type trigger_type[MAX_TRIP_COUNT];
> > > > > > -	bool trigger_enable[MAX_TRIP_COUNT];
> > > > > > -	u8 max_trigger_level;
> > > > > > -	u8 non_hw_trigger_levels;
> > > > > >  	u8 gain;
> > > > > >  	u8 reference_voltage;
> > > > > >  	u8 noise_cancel_mode;
> > > > > > @@ -110,18 +71,6 @@ struct exynos_tmu_platform_data {
> > > > > >  	u32 cal_mode;
> > > > > >  };
> > > > > >  
> > > > > > -/**
> > > > > > - * struct exynos_tmu_init_data
> > > > > > - * @tmu_count: number of TMU instances.
> > > > > > - * @tmu_data: platform data of all TMU instances.
> > > > > > - * This structure is required to store data for
> > > > > > multi-instance exynos tmu
> > > > > > - * driver.
> > > > > > - */
> > > > > > -struct exynos_tmu_init_data {
> > > > > > -	int tmu_count;
> > > > > > -	struct exynos_tmu_platform_data tmu_data[];
> > > > > > -};
> > > > > > -
> > > > > >  extern struct exynos_tmu_init_data const
> > > > > > exynos3250_default_tmu_data; extern struct
> > > > > > exynos_tmu_init_data const exynos4210_default_tmu_data;
> > > > > > extern struct exynos_tmu_init_data const
> > > > > > exynos4412_default_tmu_data; -- 2.0.0.rc2
> > > > > > 
> > > > 
> > > > 
> > > > 
> > > > -- 
> > > > Best regards,
> > > > 
> > > > Lukasz Majewski
> > > > 
> > > > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
> > 
> > 
> > 
> > -- 
> > Best regards,
> > 
> > Lukasz Majewski
> > 
> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
diff mbox

Patch

diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
index c09d830..1e47d0d 100644
--- a/drivers/thermal/samsung/Makefile
+++ b/drivers/thermal/samsung/Makefile
@@ -3,5 +3,3 @@ 
 #
 obj-$(CONFIG_EXYNOS_THERMAL)			+= exynos_thermal.o
 exynos_thermal-y				:= exynos_tmu.o
-exynos_thermal-y				+= exynos_tmu_data.o
-exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE)	+= exynos_thermal_common.o
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index ae30f6a..633a9e2 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -1,6 +1,10 @@ 
 /*
  * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit)
  *
+ *  Copyright (C) 2014 Samsung Electronics
+ *  Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
+ *  Lukasz Majewski <l.majewski@samsung.com>
+ *
  *  Copyright (C) 2011 Samsung Electronics
  *  Donggeun Kim <dg77.kim@samsung.com>
  *  Amit Daniel Kachhap <amit.kachhap@linaro.org>
@@ -31,8 +35,8 @@ 
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
-#include "exynos_thermal_common.h"
 #include "exynos_tmu.h"
+#include "../thermal_core.h"
 
 /* Exynos generic registers */
 #define EXYNOS_TMU_REG_TRIMINFO		0x0
@@ -115,6 +119,7 @@ 
 #define EXYNOS5440_TMU_TH_RISE4_SHIFT		24
 #define EXYNOS5440_EFUSE_SWAP_OFFSET		8
 
+#define MCELSIUS	1000
 /**
  * struct exynos_tmu_data : A structure to hold the private data of the TMU
 	driver
@@ -150,7 +155,8 @@  struct exynos_tmu_data {
 	struct clk *clk, *clk_sec;
 	u8 temp_error1, temp_error2;
 	struct regulator *regulator;
-	struct thermal_sensor_conf *reg_conf;
+	struct thermal_zone_device *tzd;
+
 	int (*tmu_initialize)(struct platform_device *pdev);
 	void (*tmu_control)(struct platform_device *pdev, bool on);
 	int (*tmu_read)(struct exynos_tmu_data *data);
@@ -159,6 +165,33 @@  struct exynos_tmu_data {
 	void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
 };
 
+static void exynos_report_trigger(struct exynos_tmu_data *p)
+{
+	char data[10], *envp[] = { data, NULL };
+	struct thermal_zone_device *tz = p->tzd;
+	unsigned long temp;
+	unsigned int i;
+
+	if (!p) {
+		pr_err("Wrong temperature configuration data\n");
+		return;
+	}
+
+	thermal_zone_device_update(tz);
+
+	mutex_lock(&tz->lock);
+	/* Find the level for which trip happened */
+	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
+		tz->ops->get_trip_temp(tz, i, &temp);
+		if (tz->last_temperature < temp)
+			break;
+	}
+
+	snprintf(data, sizeof(data), "%u", i);
+	kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, envp);
+	mutex_unlock(&tz->lock);
+}
+
 /*
  * TMU treats temperature as a mapped temperature code.
  * The temperature is converted differently depending on the calibration type.
@@ -234,14 +267,25 @@  static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info)
 
 static u32 get_th_reg(struct exynos_tmu_data *data, u32 threshold, bool falling)
 {
-	struct exynos_tmu_platform_data *pdata = data->pdata;
+	struct thermal_zone_device *tz = data->tzd;
+	const struct thermal_trip * const trips =
+		of_thermal_get_trip_points(tz);
+	unsigned long temp;
 	int i;
 
-	for (i = 0; i < pdata->non_hw_trigger_levels; i++) {
-		u8 temp = pdata->trigger_levels[i];
+	if (!trips) {
+		pr_err("%s: Cannot get trip points from of-thermal.c!\n",
+		       __func__);
+		return 0;
+	}
+
+	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
+		if (trips[i].type == THERMAL_TRIP_CRITICAL)
+			continue;
 
+		temp = trips[i].temperature / MCELSIUS;
 		if (falling)
-			temp -= pdata->threshold_falling;
+			temp -= (trips[i].hysteresis / MCELSIUS);
 		else
 			threshold &= ~(0xff << 8 * i);
 
@@ -305,9 +349,19 @@  static void exynos_tmu_control(struct platform_device *pdev, bool on)
 static int exynos4210_tmu_initialize(struct platform_device *pdev)
 {
 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
-	struct exynos_tmu_platform_data *pdata = data->pdata;
-	unsigned int status;
+	struct thermal_zone_device *tz = data->tzd;
+	const struct thermal_trip * const trips =
+		of_thermal_get_trip_points(tz);
 	int ret = 0, threshold_code, i;
+	unsigned long reference, temp;
+	unsigned int status;
+
+	if (!trips) {
+		pr_err("%s: Cannot get trip points from of-thermal.c!\n",
+		       __func__);
+		ret = -ENODEV;
+		goto out;
+	}
 
 	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
 	if (!status) {
@@ -318,12 +372,19 @@  static int exynos4210_tmu_initialize(struct platform_device *pdev)
 	sanitize_temp_error(data, readl(data->base + EXYNOS_TMU_REG_TRIMINFO));
 
 	/* Write temperature code for threshold */
-	threshold_code = temp_to_code(data, pdata->threshold);
+	reference = trips[0].temperature / MCELSIUS;
+	threshold_code = temp_to_code(data, reference);
+	if (threshold_code < 0) {
+		ret = threshold_code;
+		goto out;
+	}
 	writeb(threshold_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
 
-	for (i = 0; i < pdata->non_hw_trigger_levels; i++)
-		writeb(pdata->trigger_levels[i], data->base +
+	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
+		temp = trips[i].temperature / MCELSIUS;
+		writeb(temp - reference, data->base +
 		       EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
+	}
 
 	data->tmu_clear_irqs(data);
 out:
@@ -333,9 +394,11 @@  out:
 static int exynos4412_tmu_initialize(struct platform_device *pdev)
 {
 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
-	struct exynos_tmu_platform_data *pdata = data->pdata;
+	const struct thermal_trip * const trips =
+		of_thermal_get_trip_points(data->tzd);
 	unsigned int status, trim_info, con, ctrl, rising_threshold;
 	int ret = 0, threshold_code, i;
+	unsigned long crit_temp = 0;
 
 	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
 	if (!status) {
@@ -373,17 +436,29 @@  static int exynos4412_tmu_initialize(struct platform_device *pdev)
 	data->tmu_clear_irqs(data);
 
 	/* if last threshold limit is also present */
-	i = pdata->max_trigger_level - 1;
-	if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) {
-		threshold_code = temp_to_code(data, pdata->trigger_levels[i]);
-		/* 1-4 level to be assigned in th0 reg */
-		rising_threshold &= ~(0xff << 8 * i);
-		rising_threshold |= threshold_code << 8 * i;
-		writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE);
-		con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
-		con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
-		writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
+	for (i = 0; i < of_thermal_get_ntrips(data->tzd); i++) {
+		if (trips[i].type == THERMAL_TRIP_CRITICAL) {
+			crit_temp = trips[i].temperature;
+			break;
+		}
 	}
+
+	if (i == of_thermal_get_ntrips(data->tzd)) {
+		pr_err("%s: No CRITICAL trip point defined at of-thermal.c!\n",
+		       __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	threshold_code = temp_to_code(data, crit_temp / MCELSIUS);
+	/* 1-4 level to be assigned in th0 reg */
+	rising_threshold &= ~(0xff << 8 * i);
+	rising_threshold |= threshold_code << 8 * i;
+	writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE);
+	con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
+	con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
+	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
+
 out:
 	return ret;
 }
@@ -391,9 +466,9 @@  out:
 static int exynos5440_tmu_initialize(struct platform_device *pdev)
 {
 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
-	struct exynos_tmu_platform_data *pdata = data->pdata;
 	unsigned int trim_info = 0, con, rising_threshold;
-	int ret = 0, threshold_code, i;
+	int ret = 0, threshold_code;
+	unsigned long crit_temp = 0;
 
 	/*
 	 * For exynos5440 soc triminfo value is swapped between TMU0 and
@@ -422,9 +497,8 @@  static int exynos5440_tmu_initialize(struct platform_device *pdev)
 	data->tmu_clear_irqs(data);
 
 	/* if last threshold limit is also present */
-	i = pdata->max_trigger_level - 1;
-	if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) {
-		threshold_code = temp_to_code(data, pdata->trigger_levels[i]);
+	if (!data->tzd->ops->get_crit_temp(data->tzd, &crit_temp)) {
+		threshold_code = temp_to_code(data, crit_temp / MCELSIUS);
 		/* 5th level to be assigned in th2 reg */
 		rising_threshold =
 			threshold_code << EXYNOS5440_TMU_TH_RISE4_SHIFT;
@@ -442,7 +516,7 @@  static int exynos5440_tmu_initialize(struct platform_device *pdev)
 static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
 {
 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
-	struct exynos_tmu_platform_data *pdata = data->pdata;
+	struct thermal_zone_device *tz = data->tzd;
 	unsigned int con, interrupt_en;
 
 	con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));
@@ -450,10 +524,15 @@  static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
 	if (on) {
 		con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
 		interrupt_en =
-			pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
-			pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
-			pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
-			pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
+			(of_thermal_is_trip_valid(tz, 3)
+			 << EXYNOS_TMU_INTEN_RISE3_SHIFT) |
+			(of_thermal_is_trip_valid(tz, 2)
+			 << EXYNOS_TMU_INTEN_RISE2_SHIFT) |
+			(of_thermal_is_trip_valid(tz, 1)
+			 << EXYNOS_TMU_INTEN_RISE1_SHIFT) |
+			(of_thermal_is_trip_valid(tz, 0)
+			 << EXYNOS_TMU_INTEN_RISE0_SHIFT);
+
 		if (data->soc != SOC_ARCH_EXYNOS4210)
 			interrupt_en |=
 				interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
@@ -468,7 +547,7 @@  static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
 static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
 {
 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
-	struct exynos_tmu_platform_data *pdata = data->pdata;
+	struct thermal_zone_device *tz = data->tzd;
 	unsigned int con, interrupt_en;
 
 	con = get_con_reg(data, readl(data->base + EXYNOS5440_TMU_S0_7_CTRL));
@@ -476,11 +555,16 @@  static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
 	if (on) {
 		con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
 		interrupt_en =
-			pdata->trigger_enable[3] << EXYNOS5440_TMU_INTEN_RISE3_SHIFT |
-			pdata->trigger_enable[2] << EXYNOS5440_TMU_INTEN_RISE2_SHIFT |
-			pdata->trigger_enable[1] << EXYNOS5440_TMU_INTEN_RISE1_SHIFT |
-			pdata->trigger_enable[0] << EXYNOS5440_TMU_INTEN_RISE0_SHIFT;
-		interrupt_en |= interrupt_en << EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
+			(of_thermal_is_trip_valid(tz, 3)
+			 << EXYNOS5440_TMU_INTEN_RISE3_SHIFT) |
+			(of_thermal_is_trip_valid(tz, 2)
+			 << EXYNOS5440_TMU_INTEN_RISE2_SHIFT) |
+			(of_thermal_is_trip_valid(tz, 1)
+			 << EXYNOS5440_TMU_INTEN_RISE1_SHIFT) |
+			(of_thermal_is_trip_valid(tz, 0)
+			 << EXYNOS5440_TMU_INTEN_RISE0_SHIFT);
+		interrupt_en |=
+			interrupt_en << EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
 	} else {
 		con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
 		interrupt_en = 0; /* Disable all interrupts */
@@ -489,19 +573,22 @@  static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
 	writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL);
 }
 
-static int exynos_tmu_read(struct exynos_tmu_data *data)
+int exynos_get_temp(void *p, long *temp)
 {
-	int ret;
+	struct exynos_tmu_data *data = p;
+
+	if (!data)
+		return -EINVAL;
 
 	mutex_lock(&data->lock);
 	clk_enable(data->clk);
-	ret = data->tmu_read(data);
-	if (ret >= 0)
-		ret = code_to_temp(data, ret);
+
+	*temp = code_to_temp(data, data->tmu_read(data)) * MCELSIUS;
+
 	clk_disable(data->clk);
 	mutex_unlock(&data->lock);
 
-	return ret;
+	return 0;
 }
 
 #ifdef CONFIG_THERMAL_EMULATION
@@ -613,7 +700,7 @@  static void exynos_tmu_work(struct work_struct *work)
 	if (!IS_ERR(data->clk_sec))
 		clk_disable(data->clk_sec);
 
-	exynos_report_trigger(data->reg_conf);
+	exynos_report_trigger(data);
 	mutex_lock(&data->lock);
 	clk_enable(data->clk);
 
@@ -673,55 +760,89 @@  static irqreturn_t exynos_tmu_irq(int irq, void *id)
 static const struct of_device_id exynos_tmu_match[] = {
 	{
 		.compatible = "samsung,exynos3250-tmu",
-		.data = &exynos3250_default_tmu_data,
 	},
 	{
 		.compatible = "samsung,exynos4210-tmu",
-		.data = &exynos4210_default_tmu_data,
 	},
 	{
 		.compatible = "samsung,exynos4412-tmu",
-		.data = &exynos4412_default_tmu_data,
 	},
 	{
 		.compatible = "samsung,exynos5250-tmu",
-		.data = &exynos5250_default_tmu_data,
 	},
 	{
 		.compatible = "samsung,exynos5260-tmu",
-		.data = &exynos5260_default_tmu_data,
 	},
 	{
 		.compatible = "samsung,exynos5420-tmu",
-		.data = &exynos5420_default_tmu_data,
 	},
 	{
 		.compatible = "samsung,exynos5420-tmu-ext-triminfo",
-		.data = &exynos5420_default_tmu_data,
 	},
 	{
 		.compatible = "samsung,exynos5440-tmu",
-		.data = &exynos5440_default_tmu_data,
 	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, exynos_tmu_match);
 
-static inline struct  exynos_tmu_platform_data *exynos_get_driver_data(
-			struct platform_device *pdev, int id)
+static int exynos_of_get_soc_type(struct device_node *np)
 {
-	struct  exynos_tmu_init_data *data_table;
-	struct exynos_tmu_platform_data *tmu_data;
-	const struct of_device_id *match;
+	if (of_device_is_compatible(np, "samsung,exynos3250-tmu"))
+		return SOC_ARCH_EXYNOS3250;
+	else if (of_device_is_compatible(np, "samsung,exynos4210-tmu"))
+		return SOC_ARCH_EXYNOS4210;
+	else if (of_device_is_compatible(np, "samsung,exynos4412-tmu"))
+		return SOC_ARCH_EXYNOS4412;
+	else if (of_device_is_compatible(np, "samsung,exynos5250-tmu"))
+		return SOC_ARCH_EXYNOS5250;
+	else if (of_device_is_compatible(np, "samsung,exynos5260-tmu"))
+		return SOC_ARCH_EXYNOS5260;
+	else if (of_device_is_compatible(np, "samsung,exynos5420-tmu"))
+		return SOC_ARCH_EXYNOS5420;
+	else if (of_device_is_compatible(np,
+					 "samsung,exynos5420-tmu-ext-triminfo"))
+		return SOC_ARCH_EXYNOS5420_TRIMINFO;
+	else if (of_device_is_compatible(np, "samsung,exynos5440-tmu"))
+		return SOC_ARCH_EXYNOS5440;
+
+	return -EINVAL;
+}
 
-	match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
-	if (!match)
-		return NULL;
-	data_table = (struct exynos_tmu_init_data *) match->data;
-	if (!data_table || id >= data_table->tmu_count)
-		return NULL;
-	tmu_data = data_table->tmu_data;
-	return (struct exynos_tmu_platform_data *) (tmu_data + id);
+static int exynos_of_sensor_conf(struct device_node *np,
+				 struct exynos_tmu_platform_data *pdata)
+{
+	u32 value;
+	int ret;
+
+	of_node_get(np);
+
+	ret = of_property_read_u32(np, "samsung,tmu_gain", &value);
+	pdata->gain = (u8) value;
+	of_property_read_u32(np, "samsung,tmu_reference_voltage", &value);
+	pdata->reference_voltage = (u8) value;
+	of_property_read_u32(np, "samsung,tmu_noise_cancel_mode", &value);
+	pdata->noise_cancel_mode = (u8) value;
+
+	of_property_read_u32(np, "samsung,tmu_efuse_value",
+			     &pdata->efuse_value);
+	of_property_read_u32(np, "samsung,tmu_min_efuse_value",
+			     &pdata->min_efuse_value);
+	of_property_read_u32(np, "samsung,tmu_max_efuse_value",
+			     &pdata->max_efuse_value);
+
+	of_property_read_u32(np, "samsung,tmu_first_point_trim", &value);
+	pdata->first_point_trim = (u8) value;
+	of_property_read_u32(np, "samsung,tmu_second_point_trim", &value);
+	pdata->second_point_trim = (u8) value;
+	of_property_read_u32(np, "samsung,tmu_default_temp_offset", &value);
+	pdata->default_temp_offset = (u8) value;
+
+	of_property_read_u32(np, "samsung,tmu_cal_type", &pdata->cal_type);
+	of_property_read_u32(np, "samsung,tmu_cal_mode", &pdata->cal_mode);
+
+	of_node_put(np);
+	return 0;
 }
 
 static int exynos_map_dt_data(struct platform_device *pdev)
@@ -771,14 +892,15 @@  static int exynos_map_dt_data(struct platform_device *pdev)
 		return -EADDRNOTAVAIL;
 	}
 
-	pdata = exynos_get_driver_data(pdev, data->id);
-	if (!pdata) {
-		dev_err(&pdev->dev, "No platform init data supplied.\n");
-		return -ENODEV;
-	}
+	pdata = devm_kzalloc(&pdev->dev,
+			     sizeof(struct exynos_tmu_platform_data),
+			     GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
 
+	exynos_of_sensor_conf(pdev->dev.of_node, pdata);
 	data->pdata = pdata;
-	data->soc = pdata->type;
+	data->soc = exynos_of_get_soc_type(pdev->dev.of_node);
 
 	switch (data->soc) {
 	case SOC_ARCH_EXYNOS4210:
@@ -834,12 +956,16 @@  static int exynos_map_dt_data(struct platform_device *pdev)
 	return 0;
 }
 
+static struct thermal_zone_of_device_ops exynos_sensor_ops = {
+	.get_temp = exynos_get_temp,
+	.set_emul_temp = exynos_tmu_set_emulation,
+};
+
 static int exynos_tmu_probe(struct platform_device *pdev)
 {
-	struct exynos_tmu_data *data;
 	struct exynos_tmu_platform_data *pdata;
-	struct thermal_sensor_conf *sensor_conf;
-	int ret, i;
+	struct exynos_tmu_data *data;
+	int ret;
 
 	data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
 					GFP_KERNEL);
@@ -849,9 +975,15 @@  static int exynos_tmu_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, data);
 	mutex_init(&data->lock);
 
+	data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
+						    &exynos_sensor_ops);
+	if (IS_ERR(data->tzd)) {
+		pr_err("thermal: tz: %p ERROR\n", data->tzd);
+		return PTR_ERR(data->tzd);
+	}
 	ret = exynos_map_dt_data(pdev);
 	if (ret)
-		return ret;
+		goto err_sensor;
 
 	pdata = data->pdata;
 
@@ -860,20 +992,22 @@  static int exynos_tmu_probe(struct platform_device *pdev)
 	data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
 	if (IS_ERR(data->clk)) {
 		dev_err(&pdev->dev, "Failed to get clock\n");
-		return  PTR_ERR(data->clk);
+		ret = PTR_ERR(data->clk);
+		goto err_sensor;
 	}
 
 	data->clk_sec = devm_clk_get(&pdev->dev, "tmu_triminfo_apbif");
 	if (IS_ERR(data->clk_sec)) {
 		if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) {
 			dev_err(&pdev->dev, "Failed to get triminfo clock\n");
-			return PTR_ERR(data->clk_sec);
+			ret = PTR_ERR(data->clk_sec);
+			goto err_sensor;
 		}
 	} else {
 		ret = clk_prepare(data->clk_sec);
 		if (ret) {
 			dev_err(&pdev->dev, "Failed to get clock\n");
-			return ret;
+			goto err_sensor;
 		}
 	}
 
@@ -889,45 +1023,6 @@  static int exynos_tmu_probe(struct platform_device *pdev)
 		goto err_clk;
 	}
 
-	exynos_tmu_control(pdev, true);
-
-	/* Allocate a structure to register with the exynos core thermal */
-	sensor_conf = devm_kzalloc(&pdev->dev,
-				sizeof(struct thermal_sensor_conf), GFP_KERNEL);
-	if (!sensor_conf) {
-		ret = -ENOMEM;
-		goto err_clk;
-	}
-	sprintf(sensor_conf->name, "therm_zone%d", data->id);
-	sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read;
-	sensor_conf->write_emul_temp =
-		(int (*)(void *, unsigned long))exynos_tmu_set_emulation;
-	sensor_conf->driver_data = data;
-	sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] +
-			pdata->trigger_enable[1] + pdata->trigger_enable[2]+
-			pdata->trigger_enable[3];
-
-	for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
-		sensor_conf->trip_data.trip_val[i] =
-			pdata->threshold + pdata->trigger_levels[i];
-		sensor_conf->trip_data.trip_type[i] =
-					pdata->trigger_type[i];
-	}
-
-	sensor_conf->trip_data.trigger_falling = pdata->threshold_falling;
-
-	sensor_conf->dev = &pdev->dev;
-	/* Register the sensor with thermal management interface */
-	ret = exynos_register_thermal(sensor_conf);
-	if (ret) {
-		if (ret != -EPROBE_DEFER)
-			dev_err(&pdev->dev,
-				"Failed to register thermal interface: %d\n",
-				ret);
-		goto err_clk;
-	}
-	data->reg_conf = sensor_conf;
-
 	ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
 		IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
 	if (ret) {
@@ -935,21 +1030,31 @@  static int exynos_tmu_probe(struct platform_device *pdev)
 		goto err_clk;
 	}
 
+	ret = exynos_tmu_initialize(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to initialize TMU\n");
+		goto err_clk;
+	}
+	exynos_tmu_control(pdev, true);
 	return 0;
+
 err_clk:
 	clk_unprepare(data->clk);
 err_clk_sec:
 	if (!IS_ERR(data->clk_sec))
 		clk_unprepare(data->clk_sec);
+err_sensor:
+	thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
+
 	return ret;
 }
 
 static int exynos_tmu_remove(struct platform_device *pdev)
 {
 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+	struct thermal_zone_device *tzd = data->tzd;
 
-	exynos_unregister_thermal(data->reg_conf);
-
+	thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
 	exynos_tmu_control(pdev, false);
 
 	clk_unprepare(data->clk);
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index 627dec9..d876d4c 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -23,8 +23,7 @@ 
 #ifndef _EXYNOS_TMU_H
 #define _EXYNOS_TMU_H
 #include <linux/cpu_cooling.h>
-
-#include "exynos_thermal_common.h"
+#include <dt-bindings/thermal/thermal_exynos.h>
 
 enum soc_type {
 	SOC_ARCH_EXYNOS3250 = 1,
@@ -36,38 +35,9 @@  enum soc_type {
 	SOC_ARCH_EXYNOS5420_TRIMINFO,
 	SOC_ARCH_EXYNOS5440,
 };
-#include <dt-bindings/thermal/thermal_exynos.h>
 
 /**
  * struct exynos_tmu_platform_data
- * @threshold: basic temperature for generating interrupt
- *	       25 <= threshold <= 125 [unit: degree Celsius]
- * @threshold_falling: differntial value for setting threshold
- *		       of temperature falling interrupt.
- * @trigger_levels: array for each interrupt levels
- *	[unit: degree Celsius]
- *	0: temperature for trigger_level0 interrupt
- *	   condition for trigger_level0 interrupt:
- *		current temperature > threshold + trigger_levels[0]
- *	1: temperature for trigger_level1 interrupt
- *	   condition for trigger_level1 interrupt:
- *		current temperature > threshold + trigger_levels[1]
- *	2: temperature for trigger_level2 interrupt
- *	   condition for trigger_level2 interrupt:
- *		current temperature > threshold + trigger_levels[2]
- *	3: temperature for trigger_level3 interrupt
- *	   condition for trigger_level3 interrupt:
- *		current temperature > threshold + trigger_levels[3]
- * @trigger_type: defines the type of trigger. Possible values are,
- *	THROTTLE_ACTIVE trigger type
- *	THROTTLE_PASSIVE trigger type
- *	SW_TRIP trigger type
- *	HW_TRIP
- * @trigger_enable[]: array to denote which trigger levels are enabled.
- *	1 = enable trigger_level[] interrupt,
- *	0 = disable trigger_level[] interrupt
- * @max_trigger_level: max trigger level supported by the TMU
- * @non_hw_trigger_levels: number of defined non-hardware trigger levels
  * @gain: gain of amplifier in the positive-TC generator block
  *	0 < gain <= 15
  * @reference_voltage: reference voltage of amplifier
@@ -79,21 +49,12 @@  enum soc_type {
  * @efuse_value: platform defined fuse value
  * @min_efuse_value: minimum valid trimming data
  * @max_efuse_value: maximum valid trimming data
- * @first_point_trim: temp value of the first point trimming
- * @second_point_trim: temp value of the second point trimming
  * @default_temp_offset: default temperature offset in case of no trimming
  * @cal_type: calibration type for temperature
  *
  * This structure is required for configuration of exynos_tmu driver.
  */
 struct exynos_tmu_platform_data {
-	u8 threshold;
-	u8 threshold_falling;
-	u8 trigger_levels[MAX_TRIP_COUNT];
-	enum trigger_type trigger_type[MAX_TRIP_COUNT];
-	bool trigger_enable[MAX_TRIP_COUNT];
-	u8 max_trigger_level;
-	u8 non_hw_trigger_levels;
 	u8 gain;
 	u8 reference_voltage;
 	u8 noise_cancel_mode;
@@ -110,18 +71,6 @@  struct exynos_tmu_platform_data {
 	u32 cal_mode;
 };
 
-/**
- * struct exynos_tmu_init_data
- * @tmu_count: number of TMU instances.
- * @tmu_data: platform data of all TMU instances.
- * This structure is required to store data for multi-instance exynos tmu
- * driver.
- */
-struct exynos_tmu_init_data {
-	int tmu_count;
-	struct exynos_tmu_platform_data tmu_data[];
-};
-
 extern struct exynos_tmu_init_data const exynos3250_default_tmu_data;
 extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
 extern struct exynos_tmu_init_data const exynos4412_default_tmu_data;