Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 359756
b: refs/heads/master
c: bbf63be
h: refs/heads/master
v: v3
  • Loading branch information
Jonghwa Lee authored and Zhang Rui committed Jan 4, 2013
1 parent d11c068 commit 43e9197
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b8bb6cb999858043489c1ddef08eed2127559169
refs/heads/master: bbf63be4f331358173da26b888a10583fcc92ec0
53 changes: 53 additions & 0 deletions trunk/Documentation/thermal/exynos_thermal_emulation
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
EXYNOS EMULATION MODE
========================

Copyright (C) 2012 Samsung Electronics

Written by Jonghwa Lee <jonghwa3.lee@samsung.com>

Description
-----------

Exynos 4x12 (4212, 4412) and 5 series provide emulation mode for thermal management unit.
Thermal emulation mode supports software debug for TMU's operation. User can set temperature
manually with software code and TMU will read current temperature from user value not from
sensor's value.

Enabling CONFIG_EXYNOS_THERMAL_EMUL option will make this support in available.
When it's enabled, sysfs node will be created under
/sys/bus/platform/devices/'exynos device name'/ with name of 'emulation'.

The sysfs node, 'emulation', will contain value 0 for the initial state. When you input any
temperature you want to update to sysfs node, it automatically enable emulation mode and
current temperature will be changed into it.
(Exynos also supports user changable delay time which would be used to delay of
changing temperature. However, this node only uses same delay of real sensing time, 938us.)

Exynos emulation mode requires synchronous of value changing and enabling. It means when you
want to update the any value of delay or next temperature, then you have to enable emulation
mode at the same time. (Or you have to keep the mode enabling.) If you don't, it fails to
change the value to updated one and just use last succeessful value repeatedly. That's why
this node gives users the right to change termerpature only. Just one interface makes it more
simply to use.

Disabling emulation mode only requires writing value 0 to sysfs node.


TEMP 120 |
|
100 |
|
80 |
| +-----------
60 | | |
| +-------------| |
40 | | | |
| | | |
20 | | | +----------
| | | | |
0 |______________|_____________|__________|__________|_________
A A A A TIME
|<----->| |<----->| |<----->| |
| 938us | | | | | |
emulation : 0 50 | 70 | 20 | 0
current temp : sensor 50 70 20 sensor
9 changes: 9 additions & 0 deletions trunk/drivers/thermal/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ config EXYNOS_THERMAL
If you say yes here you get support for TMU (Thermal Management
Unit) on SAMSUNG EXYNOS series of SoC.

config EXYNOS_THERMAL_EMUL
bool "EXYNOS TMU emulation mode support"
depends on EXYNOS_THERMAL
help
Exynos 4412 and 4414 and 5 series has emulation mode on TMU.
Enable this option will be make sysfs node in exynos thermal platform
device directory to support emulation mode. With emulation mode sysfs
node, you can manually input temperature to TMU for simulation purpose.

config DB8500_THERMAL
bool "DB8500 thermal management"
depends on ARCH_U8500
Expand Down
103 changes: 103 additions & 0 deletions trunk/drivers/thermal/exynos_thermal.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@
#define IDLE_INTERVAL 10000
#define MCELSIUS 1000

#ifdef CONFIG_EXYNOS_THERMAL_EMUL
#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_EXYNOS_THERMAL_EMUL */

/* CPU Zone information */
#define PANIC_ZONE 4
#define WARN_ZONE 3
Expand Down Expand Up @@ -832,6 +840,94 @@ static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
return (struct exynos_tmu_platform_data *)
platform_get_device_id(pdev)->driver_data;
}

#ifdef CONFIG_EXYNOS_THERMAL_EMUL
static ssize_t exynos_tmu_emulation_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct platform_device *pdev = container_of(dev,
struct platform_device, dev);
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
unsigned int reg;
u8 temp_code;
int temp = 0;

if (data->soc == SOC_ARCH_EXYNOS4210)
goto out;

mutex_lock(&data->lock);
clk_enable(data->clk);
reg = readl(data->base + EXYNOS_EMUL_CON);
clk_disable(data->clk);
mutex_unlock(&data->lock);

if (reg & EXYNOS_EMUL_ENABLE) {
reg >>= EXYNOS_EMUL_DATA_SHIFT;
temp_code = reg & EXYNOS_EMUL_DATA_MASK;
temp = code_to_temp(data, temp_code);
}
out:
return sprintf(buf, "%d\n", temp * MCELSIUS);
}

static ssize_t exynos_tmu_emulation_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct platform_device *pdev = container_of(dev,
struct platform_device, dev);
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
unsigned int reg;
int temp;

if (data->soc == SOC_ARCH_EXYNOS4210)
goto out;

if (!sscanf(buf, "%d\n", &temp) || temp < 0)
return -EINVAL;

mutex_lock(&data->lock);
clk_enable(data->clk);

reg = readl(data->base + EXYNOS_EMUL_CON);

if (temp) {
/* Both CELSIUS and MCELSIUS type are available for input */
if (temp > MCELSIUS)
temp /= MCELSIUS;

reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
(temp_to_code(data, (temp / MCELSIUS))
<< 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);

out:
return count;
}

static DEVICE_ATTR(emulation, 0644, exynos_tmu_emulation_show,
exynos_tmu_emulation_store);
static int create_emulation_sysfs(struct device *dev)
{
return device_create_file(dev, &dev_attr_emulation);
}
static void remove_emulation_sysfs(struct device *dev)
{
device_remove_file(dev, &dev_attr_emulation);
}
#else
static inline int create_emulation_sysfs(struct device *dev) { return 0; }
static inline void remove_emulation_sysfs(struct device *dev) {}
#endif

static int __devinit exynos_tmu_probe(struct platform_device *pdev)
{
struct exynos_tmu_data *data;
Expand Down Expand Up @@ -930,6 +1026,11 @@ static int __devinit exynos_tmu_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Failed to register thermal interface\n");
goto err_clk;
}

ret = create_emulation_sysfs(&pdev->dev);
if (ret)
dev_err(&pdev->dev, "Failed to create emulation mode sysfs node\n");

return 0;
err_clk:
platform_set_drvdata(pdev, NULL);
Expand All @@ -941,6 +1042,8 @@ static int __devexit exynos_tmu_remove(struct platform_device *pdev)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);

remove_emulation_sysfs(&pdev->dev);

exynos_tmu_control(pdev, false);

exynos_unregister_thermal();
Expand Down

0 comments on commit 43e9197

Please sign in to comment.