Commit 4f0a6847 authored by Jonghwa Lee's avatar Jonghwa Lee Committed by Zhang Rui

Thermal: exynos: Add support for temperature falling interrupt.

This patch introduces using temperature falling interrupt in exynos
thermal driver. Former patch, it only use polling way to check
whether if system themperature is fallen. However, exynos SOC also
provides temperature falling interrupt way to do same things by hw.
This feature is not supported in exynos4210.
Acked-by: default avatarKukjin Kim <kgene.kim@samsung.com>
Signed-off-by: default avatarJonghwa Lee <jonghwa3.lee@samsung.com>
Signed-off-by: default avatarAmit Daniel Kachhap <amit.daniel@samsung.com>
Signed-off-by: default avatarZhang Rui <rui.zhang@intel.com>
parent 74ffa64c
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
#define SENSOR_NAME_LEN 16 #define SENSOR_NAME_LEN 16
#define MAX_TRIP_COUNT 8 #define MAX_TRIP_COUNT 8
#define MAX_COOLING_DEVICE 4 #define MAX_COOLING_DEVICE 4
#define MAX_THRESHOLD_LEVS 4
#define ACTIVE_INTERVAL 500 #define ACTIVE_INTERVAL 500
#define IDLE_INTERVAL 10000 #define IDLE_INTERVAL 10000
...@@ -133,6 +134,7 @@ struct exynos_tmu_data { ...@@ -133,6 +134,7 @@ struct exynos_tmu_data {
struct thermal_trip_point_conf { struct thermal_trip_point_conf {
int trip_val[MAX_TRIP_COUNT]; int trip_val[MAX_TRIP_COUNT];
int trip_count; int trip_count;
u8 trigger_falling;
}; };
struct thermal_cooling_conf { struct thermal_cooling_conf {
...@@ -182,7 +184,8 @@ static int exynos_set_mode(struct thermal_zone_device *thermal, ...@@ -182,7 +184,8 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
mutex_lock(&th_zone->therm_dev->lock); mutex_lock(&th_zone->therm_dev->lock);
if (mode == THERMAL_DEVICE_ENABLED) if (mode == THERMAL_DEVICE_ENABLED &&
!th_zone->sensor_conf->trip_data.trigger_falling)
th_zone->therm_dev->polling_delay = IDLE_INTERVAL; th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
else else
th_zone->therm_dev->polling_delay = 0; th_zone->therm_dev->polling_delay = 0;
...@@ -428,7 +431,8 @@ static void exynos_report_trigger(void) ...@@ -428,7 +431,8 @@ static void exynos_report_trigger(void)
break; break;
} }
if (th_zone->mode == THERMAL_DEVICE_ENABLED) { if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
!th_zone->sensor_conf->trip_data.trigger_falling) {
if (i > 0) if (i > 0)
th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL; th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
else else
...@@ -467,7 +471,8 @@ static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) ...@@ -467,7 +471,8 @@ static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name, th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0, EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
IDLE_INTERVAL); sensor_conf->trip_data.trigger_falling ?
0 : IDLE_INTERVAL);
if (IS_ERR(th_zone->therm_dev)) { if (IS_ERR(th_zone->therm_dev)) {
pr_err("Failed to register thermal zone device\n"); pr_err("Failed to register thermal zone device\n");
...@@ -574,8 +579,9 @@ static int exynos_tmu_initialize(struct platform_device *pdev) ...@@ -574,8 +579,9 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
{ {
struct exynos_tmu_data *data = platform_get_drvdata(pdev); struct exynos_tmu_data *data = platform_get_drvdata(pdev);
struct exynos_tmu_platform_data *pdata = data->pdata; struct exynos_tmu_platform_data *pdata = data->pdata;
unsigned int status, trim_info, rising_threshold; unsigned int status, trim_info;
int ret = 0, threshold_code; unsigned int rising_threshold = 0, falling_threshold = 0;
int ret = 0, threshold_code, i, trigger_levs = 0;
mutex_lock(&data->lock); mutex_lock(&data->lock);
clk_enable(data->clk); clk_enable(data->clk);
...@@ -600,6 +606,11 @@ static int exynos_tmu_initialize(struct platform_device *pdev) ...@@ -600,6 +606,11 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
(data->temp_error2 != 0)) (data->temp_error2 != 0))
data->temp_error1 = pdata->efuse_value; 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) { if (data->soc == SOC_ARCH_EXYNOS4210) {
/* Write temperature code for threshold */ /* Write temperature code for threshold */
threshold_code = temp_to_code(data, pdata->threshold); threshold_code = temp_to_code(data, pdata->threshold);
...@@ -609,44 +620,38 @@ static int exynos_tmu_initialize(struct platform_device *pdev) ...@@ -609,44 +620,38 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
} }
writeb(threshold_code, writeb(threshold_code,
data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
for (i = 0; i < trigger_levs; i++)
writeb(pdata->trigger_levels[0], writeb(pdata->trigger_levels[i],
data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0); data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
writeb(pdata->trigger_levels[1],
data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL1);
writeb(pdata->trigger_levels[2],
data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL2);
writeb(pdata->trigger_levels[3],
data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL3);
writel(EXYNOS4210_TMU_INTCLEAR_VAL, writel(EXYNOS4210_TMU_INTCLEAR_VAL,
data->base + EXYNOS_TMU_REG_INTCLEAR); data->base + EXYNOS_TMU_REG_INTCLEAR);
} else if (data->soc == SOC_ARCH_EXYNOS) { } else if (data->soc == SOC_ARCH_EXYNOS) {
/* Write temperature code for threshold */ /* Write temperature code for rising and falling threshold */
threshold_code = temp_to_code(data, pdata->trigger_levels[0]); for (i = 0; i < trigger_levs; i++) {
if (threshold_code < 0) { threshold_code = temp_to_code(data,
ret = threshold_code; pdata->trigger_levels[i]);
goto out; if (threshold_code < 0) {
} ret = threshold_code;
rising_threshold = threshold_code; goto out;
threshold_code = temp_to_code(data, pdata->trigger_levels[1]); }
if (threshold_code < 0) { rising_threshold |= threshold_code << 8 * i;
ret = threshold_code; if (pdata->threshold_falling) {
goto out; threshold_code = temp_to_code(data,
} pdata->trigger_levels[i] -
rising_threshold |= (threshold_code << 8); pdata->threshold_falling);
threshold_code = temp_to_code(data, pdata->trigger_levels[2]); if (threshold_code > 0)
if (threshold_code < 0) { falling_threshold |=
ret = threshold_code; threshold_code << 8 * i;
goto out; }
} }
rising_threshold |= (threshold_code << 16);
writel(rising_threshold, writel(rising_threshold,
data->base + EXYNOS_THD_TEMP_RISE); data->base + EXYNOS_THD_TEMP_RISE);
writel(0, data->base + EXYNOS_THD_TEMP_FALL); writel(falling_threshold,
data->base + EXYNOS_THD_TEMP_FALL);
writel(EXYNOS_TMU_CLEAR_RISE_INT|EXYNOS_TMU_CLEAR_FALL_INT, writel(EXYNOS_TMU_CLEAR_RISE_INT | EXYNOS_TMU_CLEAR_FALL_INT,
data->base + EXYNOS_TMU_REG_INTCLEAR); data->base + EXYNOS_TMU_REG_INTCLEAR);
} }
out: out:
...@@ -679,6 +684,8 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on) ...@@ -679,6 +684,8 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
pdata->trigger_level2_en << 8 | pdata->trigger_level2_en << 8 |
pdata->trigger_level1_en << 4 | pdata->trigger_level1_en << 4 |
pdata->trigger_level0_en; pdata->trigger_level0_en;
if (pdata->threshold_falling)
interrupt_en |= interrupt_en << 16;
} else { } else {
con |= EXYNOS_TMU_CORE_OFF; con |= EXYNOS_TMU_CORE_OFF;
interrupt_en = 0; /* Disable all interrupts */ interrupt_en = 0; /* Disable all interrupts */
...@@ -716,7 +723,8 @@ static void exynos_tmu_work(struct work_struct *work) ...@@ -716,7 +723,8 @@ static void exynos_tmu_work(struct work_struct *work)
mutex_lock(&data->lock); mutex_lock(&data->lock);
clk_enable(data->clk); clk_enable(data->clk);
if (data->soc == SOC_ARCH_EXYNOS) if (data->soc == SOC_ARCH_EXYNOS)
writel(EXYNOS_TMU_CLEAR_RISE_INT, writel(EXYNOS_TMU_CLEAR_RISE_INT |
EXYNOS_TMU_CLEAR_FALL_INT,
data->base + EXYNOS_TMU_REG_INTCLEAR); data->base + EXYNOS_TMU_REG_INTCLEAR);
else else
writel(EXYNOS4210_TMU_INTCLEAR_VAL, writel(EXYNOS4210_TMU_INTCLEAR_VAL,
...@@ -772,6 +780,7 @@ static struct exynos_tmu_platform_data const exynos4210_default_tmu_data = { ...@@ -772,6 +780,7 @@ static struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412) #if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
static struct exynos_tmu_platform_data const exynos_default_tmu_data = { static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
.threshold_falling = 10,
.trigger_levels[0] = 85, .trigger_levels[0] = 85,
.trigger_levels[1] = 103, .trigger_levels[1] = 103,
.trigger_levels[2] = 110, .trigger_levels[2] = 110,
...@@ -1015,6 +1024,8 @@ static int __devinit exynos_tmu_probe(struct platform_device *pdev) ...@@ -1015,6 +1024,8 @@ static int __devinit exynos_tmu_probe(struct platform_device *pdev)
exynos_sensor_conf.trip_data.trip_val[i] = exynos_sensor_conf.trip_data.trip_val[i] =
pdata->threshold + pdata->trigger_levels[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 = exynos_sensor_conf.cooling_data.freq_clip_count =
pdata->freq_tab_count; pdata->freq_tab_count;
for (i = 0; i < pdata->freq_tab_count; i++) { for (i = 0; i < pdata->freq_tab_count; i++) {
......
...@@ -53,6 +53,8 @@ struct freq_clip_table { ...@@ -53,6 +53,8 @@ struct freq_clip_table {
* struct exynos_tmu_platform_data * struct exynos_tmu_platform_data
* @threshold: basic temperature for generating interrupt * @threshold: basic temperature for generating interrupt
* 25 <= threshold <= 125 [unit: degree Celsius] * 25 <= threshold <= 125 [unit: degree Celsius]
* @threshold_falling: differntial value for setting threshold
* of temperature falling interrupt.
* @trigger_levels: array for each interrupt levels * @trigger_levels: array for each interrupt levels
* [unit: degree Celsius] * [unit: degree Celsius]
* 0: temperature for trigger_level0 interrupt * 0: temperature for trigger_level0 interrupt
...@@ -97,6 +99,7 @@ struct freq_clip_table { ...@@ -97,6 +99,7 @@ struct freq_clip_table {
*/ */
struct exynos_tmu_platform_data { struct exynos_tmu_platform_data {
u8 threshold; u8 threshold;
u8 threshold_falling;
u8 trigger_levels[4]; u8 trigger_levels[4];
bool trigger_level0_en; bool trigger_level0_en;
bool trigger_level1_en; bool trigger_level1_en;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment