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: <51C4637C.8010800@ti.com>
Date:	Fri, 21 Jun 2013 10:30:20 -0400
From:	Eduardo Valentin <eduardo.valentin@...com>
To:	amit daniel kachhap <amit.daniel@...sung.com>
CC:	Eduardo Valentin <eduardo.valentin@...com>,
	<linux-pm@...r.kernel.org>, Zhang Rui <rui.zhang@...el.com>,
	<linux-samsung-soc@...r.kernel.org>,
	<linux-kernel@...r.kernel.org>, Kukjin Kim <kgene.kim@...sung.com>,
	<jonghwa3.lee@...sung.com>
Subject: Re: [PATCH V6 04/30] thermal: exynos: Bifurcate exynos thermal common
 and tmu controller code

On 20-06-2013 21:50, amit daniel kachhap wrote:
> On Thu, Jun 20, 2013 at 12:15 AM, Eduardo Valentin
> <eduardo.valentin@...com> wrote:
>> Amit,
>>
>> On 17-06-2013 02:46, Amit Daniel Kachhap wrote:
>>> This code bifurcates exynos thermal implementation into common and sensor
>>> specific parts. The common thermal code interacts with core thermal layer and
>>> core cpufreq cooling parts and is independent of SOC specific driver. This
>>> change is needed to cleanly add support for new TMU sensors.
>>>
>>> Acked-by: Kukjin Kim <kgene.kim@...sung.com>
>>> Acked-by: Jonghwa Lee <jonghwa3.lee@...sung.com>
>>> Signed-off-by: Amit Daniel Kachhap <amit.daniel@...sung.com>
>>> ---
>>>  drivers/thermal/samsung/Kconfig                 |   19 +-
>>>  drivers/thermal/samsung/Makefile                |    4 +-
>>>  drivers/thermal/samsung/exynos_thermal.c        |  419 +----------------------
>>>  drivers/thermal/samsung/exynos_thermal_common.c |  384 +++++++++++++++++++++
>>>  drivers/thermal/samsung/exynos_thermal_common.h |   83 +++++
>>>  5 files changed, 490 insertions(+), 419 deletions(-)
>>>  create mode 100644 drivers/thermal/samsung/exynos_thermal_common.c
>>>  create mode 100644 drivers/thermal/samsung/exynos_thermal_common.h
>>>
>>> diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
>>> index 2cf31ad..f8100b1 100644
>>> --- a/drivers/thermal/samsung/Kconfig
>>> +++ b/drivers/thermal/samsung/Kconfig
>>> @@ -1,8 +1,17 @@
>>>  config EXYNOS_THERMAL
>>> -     tristate "Temperature sensor on Samsung EXYNOS"
>>> +     tristate "Exynos thermal management unit driver"
>>>       depends on ARCH_HAS_BANDGAP
>>>       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 get support for the TMU (Thermal Management
>>> +       Unit) driver for SAMSUNG EXYNOS series of soc. This driver initialises
>>> +       the TMU, reports temperature and handles cooling action if defined.
>>> +       This driver uses the exynos core thermal API's.
>>> +
>>> +config EXYNOS_THERMAL_CORE
>>> +     bool "Core thermal framework support for EXYNOS SOC's"
>>> +     depends on EXYNOS_THERMAL
>>> +     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.
>> Should this one depend on CPU_THERMAL? Is it mandatory?
> Hi Eduardo,
> 
> No it is not mandatory. If CPU_THERMAL is not present then cooling
> device is not created and only temp/trip_points etc sysfs are created.

OK.

> 
> Thanks,
> Amit Daniel
>>
>>> diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
>>> index 1fe6d93..6227d4f 100644
>>> --- a/drivers/thermal/samsung/Makefile
>>> +++ b/drivers/thermal/samsung/Makefile
>>> @@ -1,4 +1,6 @@
>>>  #
>>>  # Samsung thermal specific Makefile
>>>  #
>>> -obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
>>> +obj-$(CONFIG_EXYNOS_THERMAL)                 += exynos_soc_thermal.o
>>> +exynos_soc_thermal-y                         := exynos_thermal.o
>>> +exynos_soc_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
>>> diff --git a/drivers/thermal/samsung/exynos_thermal.c b/drivers/thermal/samsung/exynos_thermal.c
>>> index 03e4bbc..5293849 100644
>>> --- a/drivers/thermal/samsung/exynos_thermal.c
>>> +++ b/drivers/thermal/samsung/exynos_thermal.c
>>> @@ -21,23 +21,15 @@
>>>   *
>>>   */
>>>
>>> -#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/interrupt.h>
>>> +#include <linux/module.h>
>>>  #include <linux/of.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/platform_data/exynos_thermal.h>
>>> +
>>> +#include "exynos_thermal_common.h"
>>>
>>>  /* Exynos generic registers */
>>>  #define EXYNOS_TMU_REG_TRIMINFO              0x0
>>> @@ -88,16 +80,6 @@
>>>  #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
>>> @@ -106,17 +88,6 @@
>>>  #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;
>>> @@ -129,384 +100,6 @@ struct exynos_tmu_data {
>>>       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 *private_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 struct exynos_thermal_zone *th_zone;
>>> -static void exynos_unregister_thermal(void);
>>> -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)
>>> -{
>>> -     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)
>>> -{
>>> -     if (!th_zone->therm_dev) {
>>> -             pr_notice("thermal zone not registered\n");
>>> -             return 0;
>>> -     }
>>> -
>>> -     mutex_lock(&th_zone->therm_dev->lock);
>>> -
>>> -     if (mode == THERMAL_DEVICE_ENABLED &&
>>> -             !th_zone->sensor_conf->trip_data.trigger_falling)
>>> -             th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>>> -     else
>>> -             th_zone->therm_dev->polling_delay = 0;
>>> -
>>> -     mutex_unlock(&th_zone->therm_dev->lock);
>>> -
>>> -     th_zone->mode = mode;
>>> -     thermal_zone_device_update(th_zone->therm_dev);
>>> -     pr_info("thermal polling set for duration=%d msec\n",
>>> -                             th_zone->therm_dev->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)
>>> -{
>>> -     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;
>>> -}
>>> -
>>> -/* 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 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 = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
>>> -             if (level == THERMAL_CSTATE_INVALID)
>>> -                     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 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)
>>> -{
>>> -     void *data;
>>> -
>>> -     if (!th_zone->sensor_conf) {
>>> -             pr_info("Temperature sensor not initialised\n");
>>> -             return -EINVAL;
>>> -     }
>>> -     data = th_zone->sensor_conf->private_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;
>>> -
>>> -     if (!th_zone->sensor_conf) {
>>> -             pr_info("Temperature sensor not initialised\n");
>>> -             return -EINVAL;
>>> -     }
>>> -     data = th_zone->sensor_conf->private_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;
>>> -     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 0;
>>> -}
>>> -/* 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(void)
>>> -{
>>> -     unsigned int i;
>>> -     char data[10];
>>> -     char *envp[] = { data, NULL };
>>> -
>>> -     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;
>>> -
>>> -     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, NULL, &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;
>>> -
>>> -     pr_info("Exynos: Kernel Thermal management registered\n");
>>> -
>>> -     return 0;
>>> -
>>> -err_unregister:
>>> -     exynos_unregister_thermal();
>>> -     return ret;
>>> -}
>>> -
>>> -/* Un-Register with the in-kernel thermal management */
>>> -static void exynos_unregister_thermal(void)
>>> -{
>>> -     int i;
>>> -
>>> -     if (!th_zone)
>>> -             return;
>>> -
>>> -     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 management unregistered\n");
>>> -}
>>> -
>>>  /*
>>>   * TMU treats temperature as a mapped temperature code.
>>>   * The temperature is converted differently depending on the calibration type.
>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
>>> new file mode 100644
>>> index 0000000..92e50bc
>>> --- /dev/null
>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.c
>>> @@ -0,0 +1,384 @@
>>> +/*
>>> + * exynos_thermal_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/cpu_cooling.h>
>>> +#include <linux/platform_data/exynos_thermal.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/thermal.h>
>>> +
>>> +#include "exynos_thermal_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;
>>> +};
>>> +
>>> +static struct exynos_thermal_zone *th_zone;
>>> +
>>> +/* Get mode callback functions for thermal zone */
>>> +static int exynos_get_mode(struct thermal_zone_device *thermal,
>>> +                     enum thermal_device_mode *mode)
>>> +{
>>> +     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)
>>> +{
>>> +     if (!th_zone->therm_dev) {
>>> +             pr_notice("thermal zone not registered\n");
>>> +             return 0;
>>> +     }
>>> +
>>> +     mutex_lock(&th_zone->therm_dev->lock);
>>> +
>>> +     if (mode == THERMAL_DEVICE_ENABLED &&
>>> +             !th_zone->sensor_conf->trip_data.trigger_falling)
>>> +             th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
>>> +     else
>>> +             th_zone->therm_dev->polling_delay = 0;
>>> +
>>> +     mutex_unlock(&th_zone->therm_dev->lock);
>>> +
>>> +     th_zone->mode = mode;
>>> +     thermal_zone_device_update(th_zone->therm_dev);
>>> +     pr_info("thermal polling set for duration=%d msec\n",
>>> +                             th_zone->therm_dev->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)
>>> +{
>>> +     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;
>>> +}
>>> +
>>> +/* 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 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 = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
>>> +             if (level == THERMAL_CSTATE_INVALID)
>>> +                     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 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)
>>> +{
>>> +     void *data;
>>> +
>>> +     if (!th_zone->sensor_conf) {
>>> +             pr_info("Temperature sensor not initialised\n");
>>> +             return -EINVAL;
>>> +     }
>>> +     data = th_zone->sensor_conf->private_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;
>>> +
>>> +     if (!th_zone->sensor_conf) {
>>> +             pr_info("Temperature sensor not initialised\n");
>>> +             return -EINVAL;
>>> +     }
>>> +     data = th_zone->sensor_conf->private_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;
>>> +     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 0;
>>> +}
>>> +/* 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(void)
>>> +{
>>> +     unsigned int i;
>>> +     char data[10];
>>> +     char *envp[] = { data, NULL };
>>> +
>>> +     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;
>>> +     struct cpumask mask_val;
>>> +
>>> +     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, NULL, &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;
>>> +
>>> +     pr_info("Exynos: Kernel Thermal management registered\n");
>>> +
>>> +     return 0;
>>> +
>>> +err_unregister:
>>> +     exynos_unregister_thermal();
>>> +     return ret;
>>> +}
>>> +
>>> +/* Un-Register with the in-kernel thermal management */
>>> +void exynos_unregister_thermal(void)
>>> +{
>>> +     int i;
>>> +
>>> +     if (!th_zone)
>>> +             return;
>>> +
>>> +     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 management unregistered\n");
>>> +}
>>> diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
>>> new file mode 100644
>>> index 0000000..8df1848
>>> --- /dev/null
>>> +++ b/drivers/thermal/samsung/exynos_thermal_common.h
>>> @@ -0,0 +1,83 @@
>>> +/*
>>> + * exynos_thermal_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 _EXYNOS_THERMAL_COMMON_H
>>> +#define _EXYNOS_THERMAL_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;
>>> +     unsigned char 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 *private_data;
>>> +};
>>> +
>>> +/*Functions used exynos based thermal sensor driver*/
>>> +#ifdef CONFIG_EXYNOS_THERMAL_CORE
>>> +void exynos_unregister_thermal(void);
>>> +int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
>>> +void exynos_report_trigger(void);
>>> +#else
>>> +static inline void
>>> +exynos_unregister_thermal(void) { return; }
>>> +
>>> +static inline int
>>> +exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
>>> +
>>> +static inline void
>>> +exynos_report_trigger(void) { return; }
>>> +
>>> +#endif /* CONFIG_EXYNOS_THERMAL_CORE */
>>> +#endif /* _EXYNOS_THERMAL_COMMON_H */
>>>
>>
>>
>> --
>> You have got to be excited about what you are doing. (L. Lamport)
>>
>> Eduardo Valentin
>>
> 
> 


-- 
You have got to be excited about what you are doing. (L. Lamport)

Eduardo Valentin


Download attachment "signature.asc" of type "application/pgp-signature" (296 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ