lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CADGdYn7SGW+HC4JU1SN=Am8FSjFUm_GZTJJoKf6kV3imduxozg@mail.gmail.com>
Date:	Fri, 12 Apr 2013 16:39:13 +0530
From:	amit daniel kachhap <amit.daniel@...sung.com>
To:	Eduardo Valentin <eduardo.valentin@...com>
Cc:	linux-pm@...r.kernel.org,
	Thomas Abraham <thomas.abraham@...aro.org>,
	Zhang Rui <rui.zhang@...el.com>,
	linux-samsung-soc@...r.kernel.org, linux-kernel@...r.kernel.org,
	Kukjin Kim <kgene.kim@...sung.com>
Subject: Re: [4/9] thermal: exynos: Bifurcate exynos thermal common and tmu
 controller code

On Fri, Apr 12, 2013 at 2:12 AM, Eduardo Valentin
<eduardo.valentin@...com> wrote:
> Amit,
>
> On 26-03-2013 07:33, Amit Daniel Kachhap wrote:
>>
>> This code bifurcates exynos thermal implementation into common and sensor
>> specific parts as it will simplify adding support for new temperature
>> sensors. The file is named as exynos4210 because it was original SOC for
>> which this driver was developed and then later SOC's(5250, 4412) were
>> added
>> into it. This change is needed to add different TMU sensor for future
>> exynos5
>> SOC.
>>
>> Signed-off-by: Amit Daniel Kachhap <amit.daniel@...sung.com>
>>
>> ---
>> drivers/thermal/samsung/Kconfig              |   24 +-
>>   drivers/thermal/samsung/Makefile             |    4 +-
>>   drivers/thermal/samsung/exynos4210_thermal.c |  658 ++++++++++++++++
>>   drivers/thermal/samsung/exynos_common.c      |  421 ++++++++++
>>   drivers/thermal/samsung/exynos_common.h      |   73 ++
>>   drivers/thermal/samsung/exynos_thermal.c     | 1093
>> --------------------------
>>   6 files changed, 1172 insertions(+), 1101 deletions(-)
>>   create mode 100644 drivers/thermal/samsung/exynos4210_thermal.c
>>   create mode 100644 drivers/thermal/samsung/exynos_common.c
>>   create mode 100644 drivers/thermal/samsung/exynos_common.h
>>   delete mode 100644 drivers/thermal/samsung/exynos_thermal.c
>>
>> diff --git a/drivers/thermal/samsung/Kconfig
>> b/drivers/thermal/samsung/Kconfig
>> index 5737b85..cefe693 100644
>> --- a/drivers/thermal/samsung/Kconfig
>> +++ b/drivers/thermal/samsung/Kconfig
>> @@ -1,11 +1,23 @@
>>
>> -config EXYNOS_THERMAL
>> -       tristate "Temperature sensor on Samsung EXYNOS"
>> +config EXYNOS_COMMON
>> +       tristate "Common thermal support for EXYNOS SOC's"
>>         depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
>> +       help
>> +         If you say yes here you get support for EXYNOS TMU
>> +         (Thermal Management Unit) common registration/unregistration
>> +         functions to the core thermal layer and also to use the generic
>> +         cpu cooling API's.
>> +
>> +if EXYNOS_COMMON
>> +
>> +config EXYNOS4210_THERMAL
>> +       tristate "Temperature sensor on Samsung EXYNOS series SOC"
>> +       depends on (CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412 ||
>> SOC_EXYNOS5250)
>>         depends on CPU_THERMAL
>>         help
>> -         If you say yes here you get support for TMU (Thermal Management
>> -         Unit) on SAMSUNG EXYNOS series of SoC. This helps in registering
>> -         the exynos thermal driver with the core thermal layer and cpu
>> -         cooling API's.
>> +         If you say yes here you can enable TMU (Thermal Management Unit)
>> on
>> +         SAMSUNG EXYNOS 4210, 4412, 4414 and 5250 series of SoC. This
>> option
>> +         initialises the TMU controller and registers/unregisters with
>> exynos
>> +         common thermal layer.
>>
>> +endif
>> diff --git a/drivers/thermal/samsung/Makefile
>> b/drivers/thermal/samsung/Makefile
>> index fa55df5..d51d0c2 100644
>> --- a/drivers/thermal/samsung/Makefile
>> +++ b/drivers/thermal/samsung/Makefile
>> @@ -1,5 +1,5 @@
>>   #
>>   # Samsung thermal specific Makefile
>>   #
>> -obj-$(CONFIG_EXYNOS_THERMAL)   += exynos_thermal.o
>> -
>> +obj-$(CONFIG_EXYNOS_COMMON)            += exynos_common.o
>> +obj-$(CONFIG_EXYNOS4210_THERMAL)       += exynos4210_thermal.o
>
>
> Are you sure you want separated modules?
>
> If yes you have to review this patch and export the symbols from common to
> exynos4210. Saying that because it generates a compilation error:
> ERROR: "exynos_report_trigger"
> [drivers/thermal/samsung/exynos4210_thermal.ko] undefined!
> ERROR: "exynos_register_thermal"
> [drivers/thermal/samsung/exynos4210_thermal.ko] undefined!
> ERROR: "exynos_unregister_thermal"
> [drivers/thermal/samsung/exynos4210_thermal.ko] undefined!
>
> If you want separate modules, you have to EXPORT_SYMBOL those.
Ok. looks like I missed this test.
>
> You can also do what I have done for TI SoC thermal (check linux-next
> drivers/staging/ti-soc-thermal/Makefile)
ok sure.

Thanks,
Amit D
>>
>> diff --git a/drivers/thermal/samsung/exynos4210_thermal.c
>> b/drivers/thermal/samsung/exynos4210_thermal.c
>> new file mode 100644
>> index 0000000..09ea8c8
>> --- /dev/null
>> +++ b/drivers/thermal/samsung/exynos4210_thermal.c
>> @@ -0,0 +1,658 @@
>> +/*
>> + * exynos4210_thermal.c - Samsung EXYNOS 4210, 4412, 5250 TMU
>> + * (Thermal Management Unit)
>> + *
>> + *  Copyright (C) 2011 Samsung Electronics
>> + *  Donggeun Kim <dg77.kim@...sung.com>
>> + *  Amit Daniel Kachhap <amit.kachhap@...aro.org>
>> + *  Amit Daniel Kachhap <amit.daniel@...sung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
>> USA
>> + *
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/io.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kernel.h>
>> +#include <linux/kobject.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/platform_data/exynos_thermal.h>
>> +#include <linux/slab.h>
>> +#include <linux/workqueue.h>
>> +#include "exynos_common.h"
>> +
>> +/* Exynos generic registers */
>> +#define EXYNOS_TMU_REG_TRIMINFO                0x0
>> +#define EXYNOS_TMU_REG_CONTROL         0x20
>> +#define EXYNOS_TMU_REG_STATUS          0x28
>> +#define EXYNOS_TMU_REG_CURRENT_TEMP    0x40
>> +#define EXYNOS_TMU_REG_INTEN           0x70
>> +#define EXYNOS_TMU_REG_INTSTAT         0x74
>> +#define EXYNOS_TMU_REG_INTCLEAR                0x78
>> +
>> +#define EXYNOS_TMU_TRIM_TEMP_MASK      0xff
>> +#define EXYNOS_TMU_GAIN_SHIFT          8
>> +#define EXYNOS_TMU_REF_VOLTAGE_SHIFT   24
>> +#define EXYNOS_TMU_CORE_ON             3
>> +#define EXYNOS_TMU_CORE_OFF            2
>> +#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET     50
>> +
>> +/* Exynos4210 specific registers */
>> +#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP      0x44
>> +#define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
>> +#define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
>> +#define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
>> +#define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
>> +#define EXYNOS4210_TMU_REG_PAST_TEMP0  0x60
>> +#define EXYNOS4210_TMU_REG_PAST_TEMP1  0x64
>> +#define EXYNOS4210_TMU_REG_PAST_TEMP2  0x68
>> +#define EXYNOS4210_TMU_REG_PAST_TEMP3  0x6C
>> +
>> +#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK        0x1
>> +#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK        0x10
>> +#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK        0x100
>> +#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK        0x1000
>> +#define EXYNOS4210_TMU_INTCLEAR_VAL    0x1111
>> +
>> +/* Exynos5250 and Exynos4412 specific registers */
>> +#define EXYNOS_TMU_TRIMINFO_CON        0x14
>> +#define EXYNOS_THD_TEMP_RISE           0x50
>> +#define EXYNOS_THD_TEMP_FALL           0x54
>> +#define EXYNOS_EMUL_CON                0x80
>> +
>> +#define EXYNOS_TRIMINFO_RELOAD         0x1
>> +#define EXYNOS_TMU_CLEAR_RISE_INT      0x111
>> +#define EXYNOS_TMU_CLEAR_FALL_INT      (0x111 << 12)
>> +#define EXYNOS_MUX_ADDR_VALUE          6
>> +#define EXYNOS_MUX_ADDR_SHIFT          20
>> +#define EXYNOS_TMU_TRIP_MODE_SHIFT     13
>> +
>> +#define EFUSE_MIN_VALUE 40
>> +#define EFUSE_MAX_VALUE 100
>> +
>> +#ifdef CONFIG_THERMAL_EMULATION
>> +#define EXYNOS_EMUL_TIME       0x57F0
>> +#define EXYNOS_EMUL_TIME_SHIFT 16
>> +#define EXYNOS_EMUL_DATA_SHIFT 8
>> +#define EXYNOS_EMUL_DATA_MASK  0xFF
>> +#define EXYNOS_EMUL_ENABLE     0x1
>> +#endif /* CONFIG_THERMAL_EMULATION */
>> +
>> +struct exynos_tmu_data {
>> +       struct exynos_tmu_platform_data *pdata;
>> +       struct resource *mem;
>> +       void __iomem *base;
>> +       int irq;
>> +       enum soc_type soc;
>> +       struct work_struct irq_work;
>> +       struct mutex lock;
>> +       struct clk *clk;
>> +       u8 temp_error1, temp_error2;
>> +};
>> +
>> +/*
>> + * TMU treats temperature as a mapped temperature code.
>> + * The temperature is converted differently depending on the calibration
>> type.
>> + */
>> +static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
>> +{
>> +       struct exynos_tmu_platform_data *pdata = data->pdata;
>> +       int temp_code;
>> +
>> +       if (data->soc == SOC_ARCH_EXYNOS4210)
>> +               /* temp should range between 25 and 125 */
>> +               if (temp < 25 || temp > 125) {
>> +                       temp_code = -EINVAL;
>> +                       goto out;
>> +               }
>> +
>> +       switch (pdata->cal_type) {
>> +       case TYPE_TWO_POINT_TRIMMING:
>> +               temp_code = (temp - 25) *
>> +                   (data->temp_error2 - data->temp_error1) /
>> +                   (85 - 25) + data->temp_error1;
>> +               break;
>> +       case TYPE_ONE_POINT_TRIMMING:
>> +               temp_code = temp + data->temp_error1 - 25;
>> +               break;
>> +       default:
>> +               temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
>> +               break;
>> +       }
>> +out:
>> +       return temp_code;
>> +}
>> +
>> +/*
>> + * Calculate a temperature value from a temperature code.
>> + * The unit of the temperature is degree Celsius.
>> + */
>> +static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
>> +{
>> +       struct exynos_tmu_platform_data *pdata = data->pdata;
>> +       int temp;
>> +
>> +       if (data->soc == SOC_ARCH_EXYNOS4210)
>> +               /* temp_code should range between 75 and 175 */
>> +               if (temp_code < 75 || temp_code > 175) {
>> +                       temp = -ENODATA;
>> +                       goto out;
>> +               }
>> +
>> +       switch (pdata->cal_type) {
>> +       case TYPE_TWO_POINT_TRIMMING:
>> +               temp = (temp_code - data->temp_error1) * (85 - 25) /
>> +                   (data->temp_error2 - data->temp_error1) + 25;
>> +               break;
>> +       case TYPE_ONE_POINT_TRIMMING:
>> +               temp = temp_code - data->temp_error1 + 25;
>> +               break;
>> +       default:
>> +               temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
>> +               break;
>> +       }
>> +out:
>> +       return temp;
>> +}
>> +
>> +static int exynos_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, trim_info;
>> +       unsigned int rising_threshold = 0, falling_threshold = 0;
>> +       int ret = 0, threshold_code, i, trigger_levs = 0;
>> +
>> +       mutex_lock(&data->lock);
>> +       clk_enable(data->clk);
>> +
>> +       status = readb(data->base + EXYNOS_TMU_REG_STATUS);
>> +       if (!status) {
>> +               ret = -EBUSY;
>> +               goto out;
>> +       }
>> +
>> +       if (data->soc == SOC_ARCH_EXYNOS) {
>> +               __raw_writel(EXYNOS_TRIMINFO_RELOAD,
>> +                               data->base + EXYNOS_TMU_TRIMINFO_CON);
>> +       }
>> +       /* Save trimming info in order to perform calibration */
>> +       trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
>> +       data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
>> +       data->temp_error2 = ((trim_info >> 8) &
>> EXYNOS_TMU_TRIM_TEMP_MASK);
>> +
>> +       if ((EFUSE_MIN_VALUE > data->temp_error1) ||
>> +                       (data->temp_error1 > EFUSE_MAX_VALUE) ||
>> +                       (data->temp_error2 != 0))
>> +               data->temp_error1 = pdata->efuse_value;
>> +
>> +       /* Count trigger levels to be enabled */
>> +       for (i = 0; i < MAX_THRESHOLD_LEVS; i++)
>> +               if (pdata->trigger_levels[i])
>> +                       trigger_levs++;
>> +
>> +       if (data->soc == SOC_ARCH_EXYNOS4210) {
>> +               /* Write temperature code for threshold */
>> +               threshold_code = temp_to_code(data, pdata->threshold);
>> +               if (threshold_code < 0) {
>> +                       ret = threshold_code;
>> +                       goto out;
>> +               }
>> +               writeb(threshold_code,
>> +                       data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
>> +               for (i = 0; i < trigger_levs; i++)
>> +                       writeb(pdata->trigger_levels[i],
>> +                       data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i *
>> 4);
>> +
>> +               writel(EXYNOS4210_TMU_INTCLEAR_VAL,
>> +                       data->base + EXYNOS_TMU_REG_INTCLEAR);
>> +       } else if (data->soc == SOC_ARCH_EXYNOS) {
>> +               /* Write temperature code for rising and falling threshold
>> */
>> +               for (i = 0; i < trigger_levs; i++) {
>> +                       threshold_code = temp_to_code(data,
>> +                                               pdata->trigger_levels[i]);
>> +                       if (threshold_code < 0) {
>> +                               ret = threshold_code;
>> +                               goto out;
>> +                       }
>> +                       rising_threshold |= threshold_code << 8 * i;
>> +                       if (pdata->threshold_falling) {
>> +                               threshold_code = temp_to_code(data,
>> +                                               pdata->trigger_levels[i] -
>> +                                               pdata->threshold_falling);
>> +                               if (threshold_code > 0)
>> +                                       falling_threshold |=
>> +                                               threshold_code << 8 * i;
>> +                       }
>> +               }
>> +
>> +               writel(rising_threshold,
>> +                               data->base + EXYNOS_THD_TEMP_RISE);
>> +               writel(falling_threshold,
>> +                               data->base + EXYNOS_THD_TEMP_FALL);
>> +
>> +               writel(EXYNOS_TMU_CLEAR_RISE_INT |
>> EXYNOS_TMU_CLEAR_FALL_INT,
>> +                               data->base + EXYNOS_TMU_REG_INTCLEAR);
>> +       }
>> +out:
>> +       clk_disable(data->clk);
>> +       mutex_unlock(&data->lock);
>> +
>> +       return ret;
>> +}
>> +
>> +static void exynos_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;
>> +       unsigned int con, interrupt_en;
>> +
>> +       mutex_lock(&data->lock);
>> +       clk_enable(data->clk);
>> +
>> +       con = pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT |
>> +               pdata->gain << EXYNOS_TMU_GAIN_SHIFT;
>> +
>> +       if (data->soc == SOC_ARCH_EXYNOS) {
>> +               con |= pdata->noise_cancel_mode <<
>> EXYNOS_TMU_TRIP_MODE_SHIFT;
>> +               con |= (EXYNOS_MUX_ADDR_VALUE << EXYNOS_MUX_ADDR_SHIFT);
>> +       }
>> +
>> +       if (on) {
>> +               con |= EXYNOS_TMU_CORE_ON;
>> +               interrupt_en = pdata->trigger_level3_en << 12 |
>> +                       pdata->trigger_level2_en << 8 |
>> +                       pdata->trigger_level1_en << 4 |
>> +                       pdata->trigger_level0_en;
>> +               if (pdata->threshold_falling)
>> +                       interrupt_en |= interrupt_en << 16;
>> +       } else {
>> +               con |= EXYNOS_TMU_CORE_OFF;
>> +               interrupt_en = 0; /* Disable all interrupts */
>> +       }
>> +       writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
>> +       writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
>> +
>> +       clk_disable(data->clk);
>> +       mutex_unlock(&data->lock);
>> +}
>> +
>> +static int exynos_tmu_read(struct exynos_tmu_data *data)
>> +{
>> +       u8 temp_code;
>> +       int temp;
>> +
>> +       mutex_lock(&data->lock);
>> +       clk_enable(data->clk);
>> +
>> +       temp_code = readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP);
>> +       temp = code_to_temp(data, temp_code);
>> +
>> +       clk_disable(data->clk);
>> +       mutex_unlock(&data->lock);
>> +
>> +       return temp;
>> +}
>> +
>> +#ifdef CONFIG_THERMAL_EMULATION
>> +static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
>> +{
>> +       struct exynos_tmu_data *data = drv_data;
>> +       unsigned int reg;
>> +       int ret = -EINVAL;
>> +
>> +       if (data->soc == SOC_ARCH_EXYNOS4210)
>> +               goto out;
>> +
>> +       if (temp && temp < MCELSIUS)
>> +               goto out;
>> +
>> +       mutex_lock(&data->lock);
>> +       clk_enable(data->clk);
>> +
>> +       reg = readl(data->base + EXYNOS_EMUL_CON);
>> +
>> +       if (temp) {
>> +               temp /= MCELSIUS;
>> +
>> +               reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
>> +                       (temp_to_code(data, temp)
>> +                        << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
>> +       } else {
>> +               reg &= ~EXYNOS_EMUL_ENABLE;
>> +       }
>> +
>> +       writel(reg, data->base + EXYNOS_EMUL_CON);
>> +
>> +       clk_disable(data->clk);
>> +       mutex_unlock(&data->lock);
>> +       return 0;
>> +out:
>> +       return ret;
>> +}
>> +#else
>> +static int exynos_tmu_set_emulation(void *drv_data,    unsigned long
>> temp)
>> +       { return -EINVAL; }
>> +#endif/*CONFIG_THERMAL_EMULATION*/
>> +
>> +static struct thermal_sensor_conf exynos_sensor_conf = {
>> +       .name                   = "exynos-therm",
>> +       .read_temperature       = (int (*)(void *))exynos_tmu_read,
>> +       .write_emul_temp        = exynos_tmu_set_emulation,
>> +};
>> +
>> +static void exynos_tmu_work(struct work_struct *work)
>> +{
>> +       struct exynos_tmu_data *data = container_of(work,
>> +                       struct exynos_tmu_data, irq_work);
>> +
>> +       exynos_report_trigger(&exynos_sensor_conf);
>> +       mutex_lock(&data->lock);
>> +       clk_enable(data->clk);
>> +       if (data->soc == SOC_ARCH_EXYNOS)
>> +               writel(EXYNOS_TMU_CLEAR_RISE_INT |
>> +                               EXYNOS_TMU_CLEAR_FALL_INT,
>> +                               data->base + EXYNOS_TMU_REG_INTCLEAR);
>> +       else
>> +               writel(EXYNOS4210_TMU_INTCLEAR_VAL,
>> +                               data->base + EXYNOS_TMU_REG_INTCLEAR);
>> +       clk_disable(data->clk);
>> +       mutex_unlock(&data->lock);
>> +
>> +       enable_irq(data->irq);
>> +}
>> +
>> +static irqreturn_t exynos_tmu_irq(int irq, void *id)
>> +{
>> +       struct exynos_tmu_data *data = id;
>> +
>> +       disable_irq_nosync(irq);
>> +       schedule_work(&data->irq_work);
>> +
>> +       return IRQ_HANDLED;
>> +}
>> +
>> +#if defined(CONFIG_CPU_EXYNOS4210)
>> +static struct exynos_tmu_platform_data const exynos4210_default_tmu_data
>> = {
>> +       .threshold = 80,
>> +       .trigger_levels[0] = 5,
>> +       .trigger_levels[1] = 20,
>> +       .trigger_levels[2] = 30,
>> +       .trigger_level0_en = 1,
>> +       .trigger_level1_en = 1,
>> +       .trigger_level2_en = 1,
>> +       .trigger_level3_en = 0,
>> +       .gain = 15,
>> +       .reference_voltage = 7,
>> +       .cal_type = TYPE_ONE_POINT_TRIMMING,
>> +       .freq_tab[0] = {
>> +               .freq_clip_max = 800 * 1000,
>> +               .temp_level = 85,
>> +       },
>> +       .freq_tab[1] = {
>> +               .freq_clip_max = 200 * 1000,
>> +               .temp_level = 100,
>> +       },
>> +       .freq_tab_count = 2,
>> +       .type = SOC_ARCH_EXYNOS4210,
>> +};
>> +#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
>> +#else
>> +#define EXYNOS4210_TMU_DRV_DATA (NULL)
>> +#endif
>> +
>> +#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
>> +static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
>> +       .threshold_falling = 10,
>> +       .trigger_levels[0] = 85,
>> +       .trigger_levels[1] = 103,
>> +       .trigger_levels[2] = 110,
>> +       .trigger_level0_en = 1,
>> +       .trigger_level1_en = 1,
>> +       .trigger_level2_en = 1,
>> +       .trigger_level3_en = 0,
>> +       .gain = 8,
>> +       .reference_voltage = 16,
>> +       .noise_cancel_mode = 4,
>> +       .cal_type = TYPE_ONE_POINT_TRIMMING,
>> +       .efuse_value = 55,
>> +       .freq_tab[0] = {
>> +               .freq_clip_max = 800 * 1000,
>> +               .temp_level = 85,
>> +       },
>> +       .freq_tab[1] = {
>> +               .freq_clip_max = 200 * 1000,
>> +               .temp_level = 103,
>> +       },
>> +       .freq_tab_count = 2,
>> +       .type = SOC_ARCH_EXYNOS,
>> +};
>> +#define EXYNOS_TMU_DRV_DATA (&exynos_default_tmu_data)
>> +#else
>> +#define EXYNOS_TMU_DRV_DATA (NULL)
>> +#endif
>> +
>> +#ifdef CONFIG_OF
>> +static const struct of_device_id exynos_tmu_match[] = {
>> +       {
>> +               .compatible = "samsung,exynos4210-tmu",
>> +               .data = (void *)EXYNOS4210_TMU_DRV_DATA,
>> +       },
>> +       {
>> +               .compatible = "samsung,exynos5250-tmu",
>> +               .data = (void *)EXYNOS_TMU_DRV_DATA,
>> +       },
>> +       {},
>> +};
>> +MODULE_DEVICE_TABLE(of, exynos_tmu_match);
>> +#endif
>> +
>> +static struct platform_device_id exynos_tmu_driver_ids[] = {
>> +       {
>> +               .name           = "exynos4210-tmu",
>> +               .driver_data    = (kernel_ulong_t)EXYNOS4210_TMU_DRV_DATA,
>> +       },
>> +       {
>> +               .name           = "exynos5250-tmu",
>> +               .driver_data    = (kernel_ulong_t)EXYNOS_TMU_DRV_DATA,
>> +       },
>> +       { },
>> +};
>> +MODULE_DEVICE_TABLE(platform, exynos_tmu_driver_ids);
>> +
>> +static inline struct  exynos_tmu_platform_data *exynos_get_driver_data(
>> +                       struct platform_device *pdev)
>> +{
>> +#ifdef CONFIG_OF
>> +       if (pdev->dev.of_node) {
>> +               const struct of_device_id *match;
>> +               match = of_match_node(exynos_tmu_match,
>> pdev->dev.of_node);
>> +               if (!match)
>> +                       return NULL;
>> +               return (struct exynos_tmu_platform_data *) match->data;
>> +       }
>> +#endif
>> +       return (struct exynos_tmu_platform_data *)
>> +                       platform_get_device_id(pdev)->driver_data;
>> +}
>> +
>> +static int exynos_tmu_probe(struct platform_device *pdev)
>> +{
>> +       struct exynos_tmu_data *data;
>> +       struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
>> +       int ret, i;
>> +
>> +       if (!pdata)
>> +               pdata = exynos_get_driver_data(pdev);
>> +
>> +       if (!pdata) {
>> +               dev_err(&pdev->dev, "No platform init data supplied.\n");
>> +               return -ENODEV;
>> +       }
>> +       data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
>> +                                       GFP_KERNEL);
>> +       if (!data) {
>> +               dev_err(&pdev->dev, "Failed to allocate driver
>> structure\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       data->irq = platform_get_irq(pdev, 0);
>> +       if (data->irq < 0) {
>> +               dev_err(&pdev->dev, "Failed to get platform irq\n");
>> +               return data->irq;
>> +       }
>> +
>> +       INIT_WORK(&data->irq_work, exynos_tmu_work);
>> +
>> +       data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       if (!data->mem) {
>> +               dev_err(&pdev->dev, "Failed to get platform resource\n");
>> +               return -ENOENT;
>> +       }
>> +
>> +       data->base = devm_ioremap_resource(&pdev->dev, data->mem);
>> +       if (IS_ERR(data->base))
>> +               return PTR_ERR(data->base);
>> +
>> +       ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
>> +               IRQF_TRIGGER_RISING, "exynos-tmu", data);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Failed to request irq: %d\n",
>> data->irq);
>> +               return ret;
>> +       }
>> +
>> +       data->clk = clk_get(NULL, "tmu_apbif");
>> +       if (IS_ERR(data->clk)) {
>> +               dev_err(&pdev->dev, "Failed to get clock\n");
>> +               return  PTR_ERR(data->clk);
>> +       }
>> +
>> +       if (pdata->type == SOC_ARCH_EXYNOS ||
>> +                               pdata->type == SOC_ARCH_EXYNOS4210)
>> +               data->soc = pdata->type;
>> +       else {
>> +               ret = -EINVAL;
>> +               dev_err(&pdev->dev, "Platform not supported\n");
>> +               goto err_clk;
>> +       }
>> +
>> +       data->pdata = pdata;
>> +       platform_set_drvdata(pdev, data);
>> +       mutex_init(&data->lock);
>> +
>> +       ret = exynos_tmu_initialize(pdev);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Failed to initialize TMU\n");
>> +               goto err_clk;
>> +       }
>> +
>> +       exynos_tmu_control(pdev, true);
>> +
>> +       /* Register the sensor with thermal management interface */
>> +       (&exynos_sensor_conf)->driver_data = data;
>> +       exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en
>> +
>> +                       pdata->trigger_level1_en +
>> pdata->trigger_level2_en +
>> +                       pdata->trigger_level3_en;
>> +
>> +       for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
>> +               exynos_sensor_conf.trip_data.trip_val[i] =
>> +                       pdata->threshold + pdata->trigger_levels[i];
>> +
>> +       exynos_sensor_conf.trip_data.trigger_falling =
>> pdata->threshold_falling;
>> +
>> +       exynos_sensor_conf.cooling_data.freq_clip_count =
>> +                                               pdata->freq_tab_count;
>> +       for (i = 0; i < pdata->freq_tab_count; i++) {
>> +               exynos_sensor_conf.cooling_data.freq_data[i].freq_clip_max
>> =
>> +                                       pdata->freq_tab[i].freq_clip_max;
>> +               exynos_sensor_conf.cooling_data.freq_data[i].temp_level =
>> +                                       pdata->freq_tab[i].temp_level;
>> +       }
>> +
>> +       ret = exynos_register_thermal(&exynos_sensor_conf);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Failed to register thermal
>> interface\n");
>> +               goto err_clk;
>> +       }
>> +
>> +       return 0;
>> +err_clk:
>> +       platform_set_drvdata(pdev, NULL);
>> +       clk_put(data->clk);
>> +       return ret;
>> +}
>> +
>> +static int exynos_tmu_remove(struct platform_device *pdev)
>> +{
>> +       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
>> +
>> +       exynos_tmu_control(pdev, false);
>> +
>> +       exynos_unregister_thermal(&exynos_sensor_conf);
>> +
>> +       clk_put(data->clk);
>> +
>> +       platform_set_drvdata(pdev, NULL);
>> +
>> +       return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +static int exynos_tmu_suspend(struct device *dev)
>> +{
>> +       exynos_tmu_control(to_platform_device(dev), false);
>> +
>> +       return 0;
>> +}
>> +
>> +static int exynos_tmu_resume(struct device *dev)
>> +{
>> +       struct platform_device *pdev = to_platform_device(dev);
>> +
>> +       exynos_tmu_initialize(pdev);
>> +       exynos_tmu_control(pdev, true);
>> +
>> +       return 0;
>> +}
>> +
>> +static SIMPLE_DEV_PM_OPS(exynos_tmu_pm,
>> +                        exynos_tmu_suspend, exynos_tmu_resume);
>> +#define EXYNOS_TMU_PM  (&exynos_tmu_pm)
>> +#else
>> +#define EXYNOS_TMU_PM  NULL
>> +#endif
>> +
>> +static struct platform_driver exynos_tmu_driver = {
>> +       .driver = {
>> +               .name   = "exynos-tmu",
>> +               .owner  = THIS_MODULE,
>> +               .pm     = EXYNOS_TMU_PM,
>> +               .of_match_table = of_match_ptr(exynos_tmu_match),
>> +       },
>> +       .probe = exynos_tmu_probe,
>> +       .remove = exynos_tmu_remove,
>> +       .id_table = exynos_tmu_driver_ids,
>> +};
>> +
>> +module_platform_driver(exynos_tmu_driver);
>> +
>> +MODULE_DESCRIPTION("EXYNOS TMU Driver");
>> +MODULE_AUTHOR("Donggeun Kim <dg77.kim@...sung.com>");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("platform:exynos-tmu");
>> diff --git a/drivers/thermal/samsung/exynos_common.c
>> b/drivers/thermal/samsung/exynos_common.c
>> new file mode 100644
>> index 0000000..649d67c
>> --- /dev/null
>> +++ b/drivers/thermal/samsung/exynos_common.c
>> @@ -0,0 +1,421 @@
>> +/*
>> + * exynos_common.c - Samsung EXYNOS common thermal file
>> + *
>> + *  Copyright (C) 2013 Samsung Electronics
>> + *  Amit Daniel Kachhap <amit.daniel@...sung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
>> USA
>> + *
>> + */
>> +
>> +#include <linux/cpufreq.h>
>> +#include <linux/cpu_cooling.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/kobject.h>
>> +#include <linux/mutex.h>
>> +#include <linux/platform_data/exynos_thermal.h>
>> +#include <linux/slab.h>
>> +#include <linux/thermal.h>
>> +#include "exynos_common.h"
>> +
>> +struct exynos_thermal_zone {
>> +       enum thermal_device_mode mode;
>> +       struct thermal_zone_device *therm_dev;
>> +       struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
>> +       unsigned int cool_dev_size;
>> +       struct platform_device *exynos4_dev;
>> +       struct thermal_sensor_conf *sensor_conf;
>> +       bool bind;
>> +};
>> +
>> +/* Get mode callback functions for thermal zone */
>> +static int exynos_get_mode(struct thermal_zone_device *thermal,
>> +                       enum thermal_device_mode *mode)
>> +{
>> +       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> +       if (th_zone)
>> +               *mode = th_zone->mode;
>> +       return 0;
>> +}
>> +
>> +/* Set mode callback functions for thermal zone */
>> +static int exynos_set_mode(struct thermal_zone_device *thermal,
>> +                       enum thermal_device_mode mode)
>> +{
>> +       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> +       if (!th_zone) {
>> +               pr_notice("thermal zone not registered\n");
>> +               return 0;
>> +       }
>> +
>> +       mutex_lock(&thermal->lock);
>> +
>> +       if (mode == THERMAL_DEVICE_ENABLED &&
>> +               !th_zone->sensor_conf->trip_data.trigger_falling)
>> +               thermal->polling_delay = IDLE_INTERVAL;
>> +       else
>> +               thermal->polling_delay = 0;
>> +
>> +       mutex_unlock(&thermal->lock);
>> +
>> +       th_zone->mode = mode;
>> +       thermal_zone_device_update(thermal);
>> +       pr_info("thermal polling set for duration=%d msec\n",
>> +                               thermal->polling_delay);
>> +       return 0;
>> +}
>> +
>> +
>> +/* Get trip type callback functions for thermal zone */
>> +static int exynos_get_trip_type(struct thermal_zone_device *thermal, int
>> trip,
>> +                                enum thermal_trip_type *type)
>> +{
>> +       switch (GET_ZONE(trip)) {
>> +       case MONITOR_ZONE:
>> +       case WARN_ZONE:
>> +               *type = THERMAL_TRIP_ACTIVE;
>> +               break;
>> +       case PANIC_ZONE:
>> +               *type = THERMAL_TRIP_CRITICAL;
>> +               break;
>> +       default:
>> +               return -EINVAL;
>> +       }
>> +       return 0;
>> +}
>> +
>> +/* Get trip temperature callback functions for thermal zone */
>> +static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int
>> trip,
>> +                               unsigned long *temp)
>> +{
>> +       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> +
>> +       if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
>> +               return -EINVAL;
>> +
>> +       *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
>> +       /* convert the temperature into millicelsius */
>> +       *temp = *temp * MCELSIUS;
>> +
>> +       return 0;
>> +}
>> +
>> +/* Get critical temperature callback functions for thermal zone */
>> +static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
>> +                               unsigned long *temp)
>> +{
>> +       int ret;
>> +       /* Panic zone */
>> +       ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
>> +       return ret;
>> +}
>> +
>> +int exynos_get_frequency_level(unsigned int cpu, unsigned int freq)
>> +{
>> +       int i = 0, ret = -EINVAL;
>> +       struct cpufreq_frequency_table *table = NULL;
>> +#ifdef CONFIG_CPU_FREQ
>> +       table = cpufreq_frequency_get_table(cpu);
>> +#endif
>> +       if (!table)
>> +               return ret;
>> +
>> +       while (table[i].frequency != CPUFREQ_TABLE_END) {
>> +               if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
>> +                       continue;
>> +               if (table[i].frequency == freq)
>> +                       return i;
>> +               i++;
>> +       }
>> +       return ret;
>> +}
>> +
>> +/* Bind callback functions for thermal zone */
>> +static int exynos_bind(struct thermal_zone_device *thermal,
>> +                       struct thermal_cooling_device *cdev)
>> +{
>> +       int ret = 0, i, tab_size, level;
>> +       struct freq_clip_table *tab_ptr, *clip_data;
>> +       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> +       struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> +
>> +       tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
>> +       tab_size = data->cooling_data.freq_clip_count;
>> +
>> +       if (tab_ptr == NULL || tab_size == 0)
>> +               return -EINVAL;
>> +
>> +       /* find the cooling device registered*/
>> +       for (i = 0; i < th_zone->cool_dev_size; i++)
>> +               if (cdev == th_zone->cool_dev[i])
>> +                       break;
>> +
>> +       /* No matching cooling device */
>> +       if (i == th_zone->cool_dev_size)
>> +               return 0;
>> +
>> +       /* Bind the thermal zone to the cpufreq cooling device */
>> +       for (i = 0; i < tab_size; i++) {
>> +               clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
>> +               level = exynos_get_frequency_level(0,
>> clip_data->freq_clip_max);
>> +               if (level < 0)
>> +                       return 0;
>> +               switch (GET_ZONE(i)) {
>> +               case MONITOR_ZONE:
>> +               case WARN_ZONE:
>> +                       if (thermal_zone_bind_cooling_device(thermal, i,
>> cdev,
>> +                                                               level, 0))
>> {
>> +                               pr_err("error binding cdev inst %d\n", i);
>> +                               ret = -EINVAL;
>> +                       }
>> +                       th_zone->bind = true;
>> +                       break;
>> +               default:
>> +                       ret = -EINVAL;
>> +               }
>> +       }
>> +
>> +       return ret;
>> +}
>> +
>> +/* Unbind callback functions for thermal zone */
>> +static int exynos_unbind(struct thermal_zone_device *thermal,
>> +                       struct thermal_cooling_device *cdev)
>> +{
>> +       int ret = 0, i, tab_size;
>> +       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> +       struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> +
>> +       if (th_zone->bind == false)
>> +               return 0;
>> +
>> +       tab_size = data->cooling_data.freq_clip_count;
>> +
>> +       if (tab_size == 0)
>> +               return -EINVAL;
>> +
>> +       /* find the cooling device registered*/
>> +       for (i = 0; i < th_zone->cool_dev_size; i++)
>> +               if (cdev == th_zone->cool_dev[i])
>> +                       break;
>> +
>> +       /* No matching cooling device */
>> +       if (i == th_zone->cool_dev_size)
>> +               return 0;
>> +
>> +       /* Bind the thermal zone to the cpufreq cooling device */
>> +       for (i = 0; i < tab_size; i++) {
>> +               switch (GET_ZONE(i)) {
>> +               case MONITOR_ZONE:
>> +               case WARN_ZONE:
>> +                       if (thermal_zone_unbind_cooling_device(thermal, i,
>> +                                                               cdev)) {
>> +                               pr_err("error unbinding cdev inst=%d\n",
>> i);
>> +                               ret = -EINVAL;
>> +                       }
>> +                       th_zone->bind = false;
>> +                       break;
>> +               default:
>> +                       ret = -EINVAL;
>> +               }
>> +       }
>> +       return ret;
>> +}
>> +
>> +/* Get temperature callback functions for thermal zone */
>> +static int exynos_get_temp(struct thermal_zone_device *thermal,
>> +                       unsigned long *temp)
>> +{
>> +       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> +       void *data;
>> +
>> +       if (!th_zone->sensor_conf) {
>> +               pr_info("Temperature sensor not initialised\n");
>> +               return -EINVAL;
>> +       }
>> +       data = th_zone->sensor_conf->driver_data;
>> +       *temp = th_zone->sensor_conf->read_temperature(data);
>> +       /* convert the temperature into millicelsius */
>> +       *temp = *temp * MCELSIUS;
>> +       return 0;
>> +}
>> +
>> +/* Get temperature callback functions for thermal zone */
>> +static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
>> +                                               unsigned long temp)
>> +{
>> +       void *data;
>> +       int ret = -EINVAL;
>> +       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> +
>> +       if (!th_zone->sensor_conf) {
>> +               pr_info("Temperature sensor not initialised\n");
>> +               return -EINVAL;
>> +       }
>> +       data = th_zone->sensor_conf->driver_data;
>> +       if (th_zone->sensor_conf->write_emul_temp)
>> +               ret = th_zone->sensor_conf->write_emul_temp(data, temp);
>> +       return ret;
>> +}
>> +
>> +/* Get the temperature trend */
>> +static int exynos_get_trend(struct thermal_zone_device *thermal,
>> +                       int trip, enum thermal_trend *trend)
>> +{
>> +       int ret = 0;
>> +       unsigned long trip_temp;
>> +
>> +       ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       if (thermal->temperature >= trip_temp)
>> +               *trend = THERMAL_TREND_RAISE_FULL;
>> +       else
>> +               *trend = THERMAL_TREND_DROP_FULL;
>> +
>> +       return ret;
>> +}
>> +/* Operation callback functions for thermal zone */
>> +static struct thermal_zone_device_ops const exynos_dev_ops = {
>> +       .bind = exynos_bind,
>> +       .unbind = exynos_unbind,
>> +       .get_temp = exynos_get_temp,
>> +       .set_emul_temp = exynos_set_emul_temp,
>> +       .get_trend = exynos_get_trend,
>> +       .get_mode = exynos_get_mode,
>> +       .set_mode = exynos_set_mode,
>> +       .get_trip_type = exynos_get_trip_type,
>> +       .get_trip_temp = exynos_get_trip_temp,
>> +       .get_crit_temp = exynos_get_crit_temp,
>> +};
>> +
>> +/*
>> + * This function may be called from interrupt based temperature sensor
>> + * when threshold is changed.
>> + */
>> +void exynos_report_trigger(struct thermal_sensor_conf *conf)
>> +{
>> +       unsigned int i;
>> +       char data[10];
>> +       char *envp[] = { data, NULL };
>> +       struct exynos_thermal_zone *th_zone = conf->pzone_data;
>> +
>> +       if (!th_zone || !th_zone->therm_dev)
>> +               return;
>> +       if (th_zone->bind == false) {
>> +               for (i = 0; i < th_zone->cool_dev_size; i++) {
>> +                       if (!th_zone->cool_dev[i])
>> +                               continue;
>> +                       exynos_bind(th_zone->therm_dev,
>> +                                       th_zone->cool_dev[i]);
>> +               }
>> +       }
>> +
>> +       thermal_zone_device_update(th_zone->therm_dev);
>> +
>> +       mutex_lock(&th_zone->therm_dev->lock);
>> +       /* Find the level for which trip happened */
>> +       for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
>> +               if (th_zone->therm_dev->last_temperature <
>> +                       th_zone->sensor_conf->trip_data.trip_val[i] *
>> MCELSIUS)
>> +                       break;
>> +       }
>> +
>> +       if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
>> +               !th_zone->sensor_conf->trip_data.trigger_falling) {
>> +               if (i > 0)
>> +                       th_zone->therm_dev->polling_delay =
>> ACTIVE_INTERVAL;
>> +               else
>> +                       th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>> +       }
>> +
>> +       snprintf(data, sizeof(data), "%u", i);
>> +       kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE,
>> envp);
>> +       mutex_unlock(&th_zone->therm_dev->lock);
>> +}
>> +
>> +/* Register with the in-kernel thermal management */
>> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
>> +{
>> +       int ret, id;
>> +       struct cpumask mask_val;
>> +       struct exynos_thermal_zone *th_zone;
>> +
>> +       if (!sensor_conf || !sensor_conf->read_temperature) {
>> +               pr_err("Temperature sensor not initialised\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
>> +       if (!th_zone)
>> +               return -ENOMEM;
>> +
>> +       th_zone->sensor_conf = sensor_conf;
>> +       cpumask_set_cpu(0, &mask_val);
>> +       th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>> +       if (IS_ERR(th_zone->cool_dev[0])) {
>> +               pr_err("Failed to register cpufreq cooling device\n");
>> +               ret = -EINVAL;
>> +               goto err_unregister;
>> +       }
>> +       th_zone->cool_dev_size++;
>> +
>> +       th_zone->therm_dev =
>> thermal_zone_device_register(sensor_conf->name,
>> +                       EXYNOS_ZONE_COUNT, 0, th_zone, &exynos_dev_ops,
>> NULL, 0,
>> +                       sensor_conf->trip_data.trigger_falling ?
>> +                       0 : IDLE_INTERVAL);
>> +
>> +       if (IS_ERR(th_zone->therm_dev)) {
>> +               pr_err("Failed to register thermal zone device\n");
>> +               ret = PTR_ERR(th_zone->therm_dev);
>> +               goto err_unregister;
>> +       }
>> +       th_zone->mode = THERMAL_DEVICE_ENABLED;
>> +       sensor_conf->pzone_data = th_zone;
>> +       id = th_zone->therm_dev->id;
>> +
>> +       pr_info("Exynos: Kernel Thermal[%d] management registered\n", id);
>> +
>> +       return 0;
>> +
>> +err_unregister:
>> +       exynos_unregister_thermal(sensor_conf);
>> +       return ret;
>> +}
>> +
>> +/* Un-Register with the in-kernel thermal management */
>> +void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf)
>> +{
>> +       int i, id;
>> +       struct exynos_thermal_zone *th_zone = sensor_conf->pzone_data;
>> +
>> +       if (!th_zone)
>> +               return;
>> +
>> +       id = th_zone->therm_dev->id;
>> +       if (th_zone->therm_dev)
>> +               thermal_zone_device_unregister(th_zone->therm_dev);
>> +
>> +       for (i = 0; i < th_zone->cool_dev_size; i++) {
>> +               if (th_zone->cool_dev[i])
>> +                       cpufreq_cooling_unregister(th_zone->cool_dev[i]);
>> +       }
>> +
>> +       kfree(th_zone);
>> +       pr_info("Exynos: Kernel Thermal[%d] management unregistered\n",
>> id);
>> +}
>> diff --git a/drivers/thermal/samsung/exynos_common.h
>> b/drivers/thermal/samsung/exynos_common.h
>> new file mode 100644
>> index 0000000..b8d289e
>> --- /dev/null
>> +++ b/drivers/thermal/samsung/exynos_common.h
>> @@ -0,0 +1,73 @@
>> +/*
>> + * exynos_common.h - Samsung EXYNOS common header file
>> + *
>> + *  Copyright (C) 2013 Samsung Electronics
>> + *  Amit Daniel Kachhap <amit.daniel@...sung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
>> USA
>> + *
>> + */
>> +
>> +#ifndef _LINUX_EXYNOS_COMMON_H
>> +#define _LINUX_EXYNOS_COMMON_H
>> +
>> +/* In-kernel thermal framework related macros & definations */
>> +#define SENSOR_NAME_LEN        16
>> +#define MAX_TRIP_COUNT 8
>> +#define MAX_COOLING_DEVICE 4
>> +#define MAX_THRESHOLD_LEVS 4
>> +
>> +#define ACTIVE_INTERVAL 500
>> +#define IDLE_INTERVAL 10000
>> +#define MCELSIUS       1000
>> +
>> +/* CPU Zone information */
>> +#define PANIC_ZONE      4
>> +#define WARN_ZONE       3
>> +#define MONITOR_ZONE    2
>> +#define SAFE_ZONE       1
>> +
>> +#define GET_ZONE(trip) (trip + 2)
>> +#define GET_TRIP(zone) (zone - 2)
>> +
>> +#define EXYNOS_ZONE_COUNT      3
>> +
>> +struct thermal_trip_point_conf {
>> +       int trip_val[MAX_TRIP_COUNT];
>> +       int trip_count;
>> +       u8 trigger_falling;
>> +};
>> +
>> +struct thermal_cooling_conf {
>> +       struct freq_clip_table freq_data[MAX_TRIP_COUNT];
>> +       int freq_clip_count;
>> +};
>> +
>> +struct thermal_sensor_conf {
>> +       char name[SENSOR_NAME_LEN];
>> +       int (*read_temperature)(void *data);
>> +       int (*write_emul_temp)(void *drv_data, unsigned long temp);
>> +       struct thermal_trip_point_conf trip_data;
>> +       struct thermal_cooling_conf cooling_data;
>> +       void *driver_data;
>> +       void *pzone_data;
>> +};
>> +
>> +/*Functions used exynos based thermal sensor driver*/
>> +void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf);
>> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
>> +void exynos_report_trigger(struct thermal_sensor_conf *sensor_conf);
>> +int exynos_get_frequency_level(unsigned int cpu, unsigned int freq);
>> +#endif /* _LINUX_EXYNOS_COMMON_H */
>> diff --git a/drivers/thermal/samsung/exynos_thermal.c
>> b/drivers/thermal/samsung/exynos_thermal.c
>> deleted file mode 100644
>> index dc9b91b..0000000
>> --- a/drivers/thermal/samsung/exynos_thermal.c
>> +++ /dev/null
>> @@ -1,1093 +0,0 @@
>> -/*
>> - * exynos_thermal.c - Samsung EXYNOS TMU (Thermal Management Unit)
>> - *
>> - *  Copyright (C) 2011 Samsung Electronics
>> - *  Donggeun Kim <dg77.kim@...sung.com>
>> - *  Amit Daniel Kachhap <amit.kachhap@...aro.org>
>> - *
>> - * This program is free software; you can redistribute it and/or modify
>> - * it under the terms of the GNU General Public License as published by
>> - * the Free Software Foundation; either version 2 of the License, or
>> - * (at your option) any later version.
>> - *
>> - * This program is distributed in the hope that it will be useful,
>> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> - * GNU General Public License for more details.
>> - *
>> - * You should have received a copy of the GNU General Public License
>> - * along with this program; if not, write to the Free Software
>> - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
>> USA
>> - *
>> - */
>> -
>> -#include <linux/module.h>
>> -#include <linux/err.h>
>> -#include <linux/kernel.h>
>> -#include <linux/slab.h>
>> -#include <linux/platform_device.h>
>> -#include <linux/interrupt.h>
>> -#include <linux/clk.h>
>> -#include <linux/workqueue.h>
>> -#include <linux/sysfs.h>
>> -#include <linux/kobject.h>
>> -#include <linux/io.h>
>> -#include <linux/mutex.h>
>> -#include <linux/platform_data/exynos_thermal.h>
>> -#include <linux/thermal.h>
>> -#include <linux/cpufreq.h>
>> -#include <linux/cpu_cooling.h>
>> -#include <linux/of.h>
>> -
>> -#include <plat/cpu.h>
>> -
>> -/* Exynos generic registers */
>> -#define EXYNOS_TMU_REG_TRIMINFO                0x0
>> -#define EXYNOS_TMU_REG_CONTROL         0x20
>> -#define EXYNOS_TMU_REG_STATUS          0x28
>> -#define EXYNOS_TMU_REG_CURRENT_TEMP    0x40
>> -#define EXYNOS_TMU_REG_INTEN           0x70
>> -#define EXYNOS_TMU_REG_INTSTAT         0x74
>> -#define EXYNOS_TMU_REG_INTCLEAR                0x78
>> -
>> -#define EXYNOS_TMU_TRIM_TEMP_MASK      0xff
>> -#define EXYNOS_TMU_GAIN_SHIFT          8
>> -#define EXYNOS_TMU_REF_VOLTAGE_SHIFT   24
>> -#define EXYNOS_TMU_CORE_ON             3
>> -#define EXYNOS_TMU_CORE_OFF            2
>> -#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET     50
>> -
>> -/* Exynos4210 specific registers */
>> -#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP      0x44
>> -#define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
>> -#define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
>> -#define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
>> -#define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
>> -#define EXYNOS4210_TMU_REG_PAST_TEMP0  0x60
>> -#define EXYNOS4210_TMU_REG_PAST_TEMP1  0x64
>> -#define EXYNOS4210_TMU_REG_PAST_TEMP2  0x68
>> -#define EXYNOS4210_TMU_REG_PAST_TEMP3  0x6C
>> -
>> -#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK        0x1
>> -#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK        0x10
>> -#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK        0x100
>> -#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK        0x1000
>> -#define EXYNOS4210_TMU_INTCLEAR_VAL    0x1111
>> -
>> -/* Exynos5250 and Exynos4412 specific registers */
>> -#define EXYNOS_TMU_TRIMINFO_CON        0x14
>> -#define EXYNOS_THD_TEMP_RISE           0x50
>> -#define EXYNOS_THD_TEMP_FALL           0x54
>> -#define EXYNOS_EMUL_CON                0x80
>> -
>> -#define EXYNOS_TRIMINFO_RELOAD         0x1
>> -#define EXYNOS_TMU_CLEAR_RISE_INT      0x111
>> -#define EXYNOS_TMU_CLEAR_FALL_INT      (0x111 << 12)
>> -#define EXYNOS_MUX_ADDR_VALUE          6
>> -#define EXYNOS_MUX_ADDR_SHIFT          20
>> -#define EXYNOS_TMU_TRIP_MODE_SHIFT     13
>> -
>> -#define EFUSE_MIN_VALUE 40
>> -#define EFUSE_MAX_VALUE 100
>> -
>> -/* In-kernel thermal framework related macros & definations */
>> -#define SENSOR_NAME_LEN        16
>> -#define MAX_TRIP_COUNT 8
>> -#define MAX_COOLING_DEVICE 4
>> -#define MAX_THRESHOLD_LEVS 4
>> -
>> -#define ACTIVE_INTERVAL 500
>> -#define IDLE_INTERVAL 10000
>> -#define MCELSIUS       1000
>> -
>> -#ifdef CONFIG_THERMAL_EMULATION
>> -#define EXYNOS_EMUL_TIME       0x57F0
>> -#define EXYNOS_EMUL_TIME_SHIFT 16
>> -#define EXYNOS_EMUL_DATA_SHIFT 8
>> -#define EXYNOS_EMUL_DATA_MASK  0xFF
>> -#define EXYNOS_EMUL_ENABLE     0x1
>> -#endif /* CONFIG_THERMAL_EMULATION */
>> -
>> -/* CPU Zone information */
>> -#define PANIC_ZONE      4
>> -#define WARN_ZONE       3
>> -#define MONITOR_ZONE    2
>> -#define SAFE_ZONE       1
>> -
>> -#define GET_ZONE(trip) (trip + 2)
>> -#define GET_TRIP(zone) (zone - 2)
>> -
>> -#define EXYNOS_ZONE_COUNT      3
>> -
>> -struct exynos_tmu_data {
>> -       struct exynos_tmu_platform_data *pdata;
>> -       struct resource *mem;
>> -       void __iomem *base;
>> -       int irq;
>> -       enum soc_type soc;
>> -       struct work_struct irq_work;
>> -       struct mutex lock;
>> -       struct clk *clk;
>> -       u8 temp_error1, temp_error2;
>> -};
>> -
>> -struct thermal_trip_point_conf {
>> -       int trip_val[MAX_TRIP_COUNT];
>> -       int trip_count;
>> -       u8 trigger_falling;
>> -};
>> -
>> -struct thermal_cooling_conf {
>> -       struct freq_clip_table freq_data[MAX_TRIP_COUNT];
>> -       int freq_clip_count;
>> -};
>> -
>> -struct thermal_sensor_conf {
>> -       char name[SENSOR_NAME_LEN];
>> -       int (*read_temperature)(void *data);
>> -       int (*write_emul_temp)(void *drv_data, unsigned long temp);
>> -       struct thermal_trip_point_conf trip_data;
>> -       struct thermal_cooling_conf cooling_data;
>> -       void *driver_data;
>> -       void *pzone_data;
>> -};
>> -
>> -struct exynos_thermal_zone {
>> -       enum thermal_device_mode mode;
>> -       struct thermal_zone_device *therm_dev;
>> -       struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
>> -       unsigned int cool_dev_size;
>> -       struct platform_device *exynos4_dev;
>> -       struct thermal_sensor_conf *sensor_conf;
>> -       bool bind;
>> -};
>> -
>> -static void exynos_unregister_thermal(struct thermal_sensor_conf
>> *sensor_conf);
>> -static int exynos_register_thermal(struct thermal_sensor_conf
>> *sensor_conf);
>> -
>> -/* Get mode callback functions for thermal zone */
>> -static int exynos_get_mode(struct thermal_zone_device *thermal,
>> -                       enum thermal_device_mode *mode)
>> -{
>> -       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> -       if (th_zone)
>> -               *mode = th_zone->mode;
>> -       return 0;
>> -}
>> -
>> -/* Set mode callback functions for thermal zone */
>> -static int exynos_set_mode(struct thermal_zone_device *thermal,
>> -                       enum thermal_device_mode mode)
>> -{
>> -       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> -       if (!th_zone) {
>> -               pr_notice("thermal zone not registered\n");
>> -               return 0;
>> -       }
>> -
>> -       mutex_lock(&thermal->lock);
>> -
>> -       if (mode == THERMAL_DEVICE_ENABLED &&
>> -               !th_zone->sensor_conf->trip_data.trigger_falling)
>> -               thermal->polling_delay = IDLE_INTERVAL;
>> -       else
>> -               thermal->polling_delay = 0;
>> -
>> -       mutex_unlock(&thermal->lock);
>> -
>> -       th_zone->mode = mode;
>> -       thermal_zone_device_update(thermal);
>> -       pr_info("thermal polling set for duration=%d msec\n",
>> -                               thermal->polling_delay);
>> -       return 0;
>> -}
>> -
>> -
>> -/* Get trip type callback functions for thermal zone */
>> -static int exynos_get_trip_type(struct thermal_zone_device *thermal, int
>> trip,
>> -                                enum thermal_trip_type *type)
>> -{
>> -       switch (GET_ZONE(trip)) {
>> -       case MONITOR_ZONE:
>> -       case WARN_ZONE:
>> -               *type = THERMAL_TRIP_ACTIVE;
>> -               break;
>> -       case PANIC_ZONE:
>> -               *type = THERMAL_TRIP_CRITICAL;
>> -               break;
>> -       default:
>> -               return -EINVAL;
>> -       }
>> -       return 0;
>> -}
>> -
>> -/* Get trip temperature callback functions for thermal zone */
>> -static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int
>> trip,
>> -                               unsigned long *temp)
>> -{
>> -       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> -
>> -       if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
>> -               return -EINVAL;
>> -
>> -       *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
>> -       /* convert the temperature into millicelsius */
>> -       *temp = *temp * MCELSIUS;
>> -
>> -       return 0;
>> -}
>> -
>> -/* Get critical temperature callback functions for thermal zone */
>> -static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
>> -                               unsigned long *temp)
>> -{
>> -       int ret;
>> -       /* Panic zone */
>> -       ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
>> -       return ret;
>> -}
>> -
>> -static int exynos_get_frequency_level(unsigned int cpu, unsigned int
>> freq)
>> -{
>> -       int i = 0, ret = -EINVAL;
>> -       struct cpufreq_frequency_table *table = NULL;
>> -#ifdef CONFIG_CPU_FREQ
>> -       table = cpufreq_frequency_get_table(cpu);
>> -#endif
>> -       if (!table)
>> -               return ret;
>> -
>> -       while (table[i].frequency != CPUFREQ_TABLE_END) {
>> -               if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
>> -                       continue;
>> -               if (table[i].frequency == freq)
>> -                       return i;
>> -               i++;
>> -       }
>> -       return ret;
>> -}
>> -
>> -/* Bind callback functions for thermal zone */
>> -static int exynos_bind(struct thermal_zone_device *thermal,
>> -                       struct thermal_cooling_device *cdev)
>> -{
>> -       int ret = 0, i, tab_size, level;
>> -       struct freq_clip_table *tab_ptr, *clip_data;
>> -       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> -       struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> -
>> -       tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
>> -       tab_size = data->cooling_data.freq_clip_count;
>> -
>> -       if (tab_ptr == NULL || tab_size == 0)
>> -               return -EINVAL;
>> -
>> -       /* find the cooling device registered*/
>> -       for (i = 0; i < th_zone->cool_dev_size; i++)
>> -               if (cdev == th_zone->cool_dev[i])
>> -                       break;
>> -
>> -       /* No matching cooling device */
>> -       if (i == th_zone->cool_dev_size)
>> -               return 0;
>> -
>> -       /* Bind the thermal zone to the cpufreq cooling device */
>> -       for (i = 0; i < tab_size; i++) {
>> -               clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
>> -               level = exynos_get_frequency_level(0,
>> clip_data->freq_clip_max);
>> -               if (level < 0)
>> -                       return 0;
>> -               switch (GET_ZONE(i)) {
>> -               case MONITOR_ZONE:
>> -               case WARN_ZONE:
>> -                       if (thermal_zone_bind_cooling_device(thermal, i,
>> cdev,
>> -                                                               level, 0))
>> {
>> -                               pr_err("error binding cdev inst %d\n", i);
>> -                               ret = -EINVAL;
>> -                       }
>> -                       th_zone->bind = true;
>> -                       break;
>> -               default:
>> -                       ret = -EINVAL;
>> -               }
>> -       }
>> -
>> -       return ret;
>> -}
>> -
>> -/* Unbind callback functions for thermal zone */
>> -static int exynos_unbind(struct thermal_zone_device *thermal,
>> -                       struct thermal_cooling_device *cdev)
>> -{
>> -       int ret = 0, i, tab_size;
>> -       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> -       struct thermal_sensor_conf *data = th_zone->sensor_conf;
>> -
>> -       if (th_zone->bind == false)
>> -               return 0;
>> -
>> -       tab_size = data->cooling_data.freq_clip_count;
>> -
>> -       if (tab_size == 0)
>> -               return -EINVAL;
>> -
>> -       /* find the cooling device registered*/
>> -       for (i = 0; i < th_zone->cool_dev_size; i++)
>> -               if (cdev == th_zone->cool_dev[i])
>> -                       break;
>> -
>> -       /* No matching cooling device */
>> -       if (i == th_zone->cool_dev_size)
>> -               return 0;
>> -
>> -       /* Bind the thermal zone to the cpufreq cooling device */
>> -       for (i = 0; i < tab_size; i++) {
>> -               switch (GET_ZONE(i)) {
>> -               case MONITOR_ZONE:
>> -               case WARN_ZONE:
>> -                       if (thermal_zone_unbind_cooling_device(thermal, i,
>> -                                                               cdev)) {
>> -                               pr_err("error unbinding cdev inst=%d\n",
>> i);
>> -                               ret = -EINVAL;
>> -                       }
>> -                       th_zone->bind = false;
>> -                       break;
>> -               default:
>> -                       ret = -EINVAL;
>> -               }
>> -       }
>> -       return ret;
>> -}
>> -
>> -/* Get temperature callback functions for thermal zone */
>> -static int exynos_get_temp(struct thermal_zone_device *thermal,
>> -                       unsigned long *temp)
>> -{
>> -       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> -       void *data;
>> -
>> -       if (!th_zone->sensor_conf) {
>> -               pr_info("Temperature sensor not initialised\n");
>> -               return -EINVAL;
>> -       }
>> -       data = th_zone->sensor_conf->driver_data;
>> -       *temp = th_zone->sensor_conf->read_temperature(data);
>> -       /* convert the temperature into millicelsius */
>> -       *temp = *temp * MCELSIUS;
>> -       return 0;
>> -}
>> -
>> -/* Get temperature callback functions for thermal zone */
>> -static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
>> -                                               unsigned long temp)
>> -{
>> -       void *data;
>> -       int ret = -EINVAL;
>> -       struct exynos_thermal_zone *th_zone = thermal->devdata;
>> -
>> -       if (!th_zone->sensor_conf) {
>> -               pr_info("Temperature sensor not initialised\n");
>> -               return -EINVAL;
>> -       }
>> -       data = th_zone->sensor_conf->driver_data;
>> -       if (th_zone->sensor_conf->write_emul_temp)
>> -               ret = th_zone->sensor_conf->write_emul_temp(data, temp);
>> -       return ret;
>> -}
>> -
>> -/* Get the temperature trend */
>> -static int exynos_get_trend(struct thermal_zone_device *thermal,
>> -                       int trip, enum thermal_trend *trend)
>> -{
>> -       int ret = 0;
>> -       unsigned long trip_temp;
>> -
>> -       ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
>> -       if (ret < 0)
>> -               return ret;
>> -
>> -       if (thermal->temperature >= trip_temp)
>> -               *trend = THERMAL_TREND_RAISE_FULL;
>> -       else
>> -               *trend = THERMAL_TREND_DROP_FULL;
>> -
>> -       return ret;
>> -}
>> -/* Operation callback functions for thermal zone */
>> -static struct thermal_zone_device_ops const exynos_dev_ops = {
>> -       .bind = exynos_bind,
>> -       .unbind = exynos_unbind,
>> -       .get_temp = exynos_get_temp,
>> -       .set_emul_temp = exynos_set_emul_temp,
>> -       .get_trend = exynos_get_trend,
>> -       .get_mode = exynos_get_mode,
>> -       .set_mode = exynos_set_mode,
>> -       .get_trip_type = exynos_get_trip_type,
>> -       .get_trip_temp = exynos_get_trip_temp,
>> -       .get_crit_temp = exynos_get_crit_temp,
>> -};
>> -
>> -/*
>> - * This function may be called from interrupt based temperature sensor
>> - * when threshold is changed.
>> - */
>> -static void exynos_report_trigger(struct thermal_sensor_conf *conf)
>> -{
>> -       unsigned int i;
>> -       char data[10];
>> -       char *envp[] = { data, NULL };
>> -       struct exynos_thermal_zone *th_zone = conf->pzone_data;
>> -
>> -       if (!th_zone || !th_zone->therm_dev)
>> -               return;
>> -       if (th_zone->bind == false) {
>> -               for (i = 0; i < th_zone->cool_dev_size; i++) {
>> -                       if (!th_zone->cool_dev[i])
>> -                               continue;
>> -                       exynos_bind(th_zone->therm_dev,
>> -                                       th_zone->cool_dev[i]);
>> -               }
>> -       }
>> -
>> -       thermal_zone_device_update(th_zone->therm_dev);
>> -
>> -       mutex_lock(&th_zone->therm_dev->lock);
>> -       /* Find the level for which trip happened */
>> -       for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
>> -               if (th_zone->therm_dev->last_temperature <
>> -                       th_zone->sensor_conf->trip_data.trip_val[i] *
>> MCELSIUS)
>> -                       break;
>> -       }
>> -
>> -       if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
>> -               !th_zone->sensor_conf->trip_data.trigger_falling) {
>> -               if (i > 0)
>> -                       th_zone->therm_dev->polling_delay =
>> ACTIVE_INTERVAL;
>> -               else
>> -                       th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>> -       }
>> -
>> -       snprintf(data, sizeof(data), "%u", i);
>> -       kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE,
>> envp);
>> -       mutex_unlock(&th_zone->therm_dev->lock);
>> -}
>> -
>> -/* Register with the in-kernel thermal management */
>> -static int exynos_register_thermal(struct thermal_sensor_conf
>> *sensor_conf)
>> -{
>> -       int ret;
>> -       struct cpumask mask_val;
>> -       struct exynos_thermal_zone *th_zone;
>> -
>> -       if (!sensor_conf || !sensor_conf->read_temperature) {
>> -               pr_err("Temperature sensor not initialised\n");
>> -               return -EINVAL;
>> -       }
>> -
>> -       th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
>> -       if (!th_zone)
>> -               return -ENOMEM;
>> -
>> -       th_zone->sensor_conf = sensor_conf;
>> -       cpumask_set_cpu(0, &mask_val);
>> -       th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
>> -       if (IS_ERR(th_zone->cool_dev[0])) {
>> -               pr_err("Failed to register cpufreq cooling device\n");
>> -               ret = -EINVAL;
>> -               goto err_unregister;
>> -       }
>> -       th_zone->cool_dev_size++;
>> -
>> -       th_zone->therm_dev =
>> thermal_zone_device_register(sensor_conf->name,
>> -                       EXYNOS_ZONE_COUNT, 0, th_zone, &exynos_dev_ops,
>> NULL, 0,
>> -                       sensor_conf->trip_data.trigger_falling ?
>> -                       0 : IDLE_INTERVAL);
>> -
>> -       if (IS_ERR(th_zone->therm_dev)) {
>> -               pr_err("Failed to register thermal zone device\n");
>> -               ret = PTR_ERR(th_zone->therm_dev);
>> -               goto err_unregister;
>> -       }
>> -       th_zone->mode = THERMAL_DEVICE_ENABLED;
>> -       sensor_conf->pzone_data = th_zone;
>> -
>> -       pr_info("Exynos: Kernel Thermal management registered\n");
>> -
>> -       return 0;
>> -
>> -err_unregister:
>> -       exynos_unregister_thermal(sensor_conf);
>> -       return ret;
>> -}
>> -
>> -/* Un-Register with the in-kernel thermal management */
>> -static void exynos_unregister_thermal(struct thermal_sensor_conf
>> *sensor_conf)
>> -{
>> -       int i;
>> -       struct exynos_thermal_zone *th_zone = sensor_conf->pzone_data;
>> -
>> -       if (!th_zone)
>> -               return;
>> -
>> -       if (th_zone->therm_dev)
>> -               thermal_zone_device_unregister(th_zone->therm_dev);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ