提交 f22d9c03 编写于 作者: A Amit Daniel Kachhap 提交者: Zhang Rui

thermal: exynos5: add exynos5250 thermal sensor driver support

Insert exynos5 TMU sensor changes into the thermal driver.  Some exynos4
changes are made generic for exynos series.

[akpm@linux-foundation.org: fix comment layout]
Signed-off-by: NSangWook Ju <sw.ju@samsung.com>
Signed-off-by: NAmit Daniel Kachhap <amit.kachhap@linaro.org>
Acked-by: NGuenter Roeck <guenter.roeck@ericsson.com>
Cc: Durgadoss <durgadoss.r@intel.com>
Cc: Len Brown <lenb@kernel.org>
Cc: Jean Delvare <khali@linux-fr.org>
Cc: Kyungmin Park <kmpark@infradead.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NAmit Daniel Kachhap <amit.daniel@samsung.com>
Signed-off-by: NZhang Rui <rui.zhang@intel.com>
上级 c48cbba6
...@@ -49,7 +49,7 @@ config RCAR_THERMAL ...@@ -49,7 +49,7 @@ config RCAR_THERMAL
config EXYNOS_THERMAL config EXYNOS_THERMAL
tristate "Temperature sensor on Samsung EXYNOS" tristate "Temperature sensor on Samsung EXYNOS"
depends on ARCH_EXYNOS4 && THERMAL depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5) && THERMAL
help help
If you say yes here you get support for TMU (Thermal Managment If you say yes here you get support for TMU (Thermal Managment
Unit) on SAMSUNG EXYNOS series of SoC. Unit) on SAMSUNG EXYNOS series of SoC.
...@@ -33,44 +33,83 @@ ...@@ -33,44 +33,83 @@
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/platform_data/exynos_thermal.h> #include <linux/platform_data/exynos_thermal.h>
#include <linux/of.h>
#define EXYNOS4_TMU_REG_TRIMINFO 0x0
#define EXYNOS4_TMU_REG_CONTROL 0x20 #include <plat/cpu.h>
#define EXYNOS4_TMU_REG_STATUS 0x28
#define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40 /* Exynos generic registers */
#define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44 #define EXYNOS_TMU_REG_TRIMINFO 0x0
#define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50 #define EXYNOS_TMU_REG_CONTROL 0x20
#define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54 #define EXYNOS_TMU_REG_STATUS 0x28
#define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58 #define EXYNOS_TMU_REG_CURRENT_TEMP 0x40
#define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C #define EXYNOS_TMU_REG_INTEN 0x70
#define EXYNOS4_TMU_REG_PAST_TEMP0 0x60 #define EXYNOS_TMU_REG_INTSTAT 0x74
#define EXYNOS4_TMU_REG_PAST_TEMP1 0x64 #define EXYNOS_TMU_REG_INTCLEAR 0x78
#define EXYNOS4_TMU_REG_PAST_TEMP2 0x68
#define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C #define EXYNOS_TMU_TRIM_TEMP_MASK 0xff
#define EXYNOS4_TMU_REG_INTEN 0x70 #define EXYNOS_TMU_GAIN_SHIFT 8
#define EXYNOS4_TMU_REG_INTSTAT 0x74 #define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24
#define EXYNOS4_TMU_REG_INTCLEAR 0x78 #define EXYNOS_TMU_CORE_ON 3
#define EXYNOS_TMU_CORE_OFF 2
#define EXYNOS4_TMU_GAIN_SHIFT 8 #define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET 50
#define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24
/* Exynos4210 specific registers */
#define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff #define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44
#define EXYNOS4_TMU_CORE_ON 3 #define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
#define EXYNOS4_TMU_CORE_OFF 2 #define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
#define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50 #define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
#define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1 #define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
#define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10 #define EXYNOS4210_TMU_REG_PAST_TEMP0 0x60
#define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100 #define EXYNOS4210_TMU_REG_PAST_TEMP1 0x64
#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000 #define EXYNOS4210_TMU_REG_PAST_TEMP2 0x68
#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111 #define EXYNOS4210_TMU_REG_PAST_TEMP3 0x6C
struct exynos4_tmu_data { #define EXYNOS4210_TMU_TRIG_LEVEL0_MASK 0x1
struct exynos4_tmu_platform_data *pdata; #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 << 16)
#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 ACTIVE_INTERVAL 500
#define IDLE_INTERVAL 10000
/* 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)
struct exynos_tmu_data {
struct exynos_tmu_platform_data *pdata;
struct resource *mem; struct resource *mem;
void __iomem *base; void __iomem *base;
int irq; int irq;
enum soc_type soc;
struct work_struct irq_work; struct work_struct irq_work;
struct mutex lock; struct mutex lock;
struct clk *clk; struct clk *clk;
...@@ -81,16 +120,17 @@ struct exynos4_tmu_data { ...@@ -81,16 +120,17 @@ struct exynos4_tmu_data {
* TMU treats temperature as a mapped temperature code. * TMU treats temperature as a mapped temperature code.
* The temperature is converted differently depending on the calibration type. * The temperature is converted differently depending on the calibration type.
*/ */
static int temp_to_code(struct exynos4_tmu_data *data, u8 temp) static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
{ {
struct exynos4_tmu_platform_data *pdata = data->pdata; struct exynos_tmu_platform_data *pdata = data->pdata;
int temp_code; int temp_code;
/* temp should range between 25 and 125 */ if (data->soc == SOC_ARCH_EXYNOS4210)
if (temp < 25 || temp > 125) { /* temp should range between 25 and 125 */
temp_code = -EINVAL; if (temp < 25 || temp > 125) {
goto out; temp_code = -EINVAL;
} goto out;
}
switch (pdata->cal_type) { switch (pdata->cal_type) {
case TYPE_TWO_POINT_TRIMMING: case TYPE_TWO_POINT_TRIMMING:
...@@ -102,7 +142,7 @@ static int temp_to_code(struct exynos4_tmu_data *data, u8 temp) ...@@ -102,7 +142,7 @@ static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
temp_code = temp + data->temp_error1 - 25; temp_code = temp + data->temp_error1 - 25;
break; break;
default: default:
temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET; temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
break; break;
} }
out: out:
...@@ -113,16 +153,17 @@ static int temp_to_code(struct exynos4_tmu_data *data, u8 temp) ...@@ -113,16 +153,17 @@ static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
* Calculate a temperature value from a temperature code. * Calculate a temperature value from a temperature code.
* The unit of the temperature is degree Celsius. * The unit of the temperature is degree Celsius.
*/ */
static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code) static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
{ {
struct exynos4_tmu_platform_data *pdata = data->pdata; struct exynos_tmu_platform_data *pdata = data->pdata;
int temp; int temp;
/* temp_code should range between 75 and 175 */ if (data->soc == SOC_ARCH_EXYNOS4210)
if (temp_code < 75 || temp_code > 175) { /* temp_code should range between 75 and 175 */
temp = -ENODATA; if (temp_code < 75 || temp_code > 175) {
goto out; temp = -ENODATA;
} goto out;
}
switch (pdata->cal_type) { switch (pdata->cal_type) {
case TYPE_TWO_POINT_TRIMMING: case TYPE_TWO_POINT_TRIMMING:
...@@ -133,54 +174,92 @@ static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code) ...@@ -133,54 +174,92 @@ static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
temp = temp_code - data->temp_error1 + 25; temp = temp_code - data->temp_error1 + 25;
break; break;
default: default:
temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET; temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
break; break;
} }
out: out:
return temp; return temp;
} }
static int exynos4_tmu_initialize(struct platform_device *pdev) static int exynos_tmu_initialize(struct platform_device *pdev)
{ {
struct exynos4_tmu_data *data = platform_get_drvdata(pdev); struct exynos_tmu_data *data = platform_get_drvdata(pdev);
struct exynos4_tmu_platform_data *pdata = data->pdata; struct exynos_tmu_platform_data *pdata = data->pdata;
unsigned int status, trim_info; unsigned int status, trim_info, rising_threshold;
int ret = 0, threshold_code; int ret = 0, threshold_code;
mutex_lock(&data->lock); mutex_lock(&data->lock);
clk_enable(data->clk); clk_enable(data->clk);
status = readb(data->base + EXYNOS4_TMU_REG_STATUS); status = readb(data->base + EXYNOS_TMU_REG_STATUS);
if (!status) { if (!status) {
ret = -EBUSY; ret = -EBUSY;
goto out; 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 */ /* Save trimming info in order to perform calibration */
trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO); trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK; data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK); data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
/* Write temperature code for threshold */ if ((EFUSE_MIN_VALUE > data->temp_error1) ||
threshold_code = temp_to_code(data, pdata->threshold); (data->temp_error1 > EFUSE_MAX_VALUE) ||
if (threshold_code < 0) { (data->temp_error2 != 0))
ret = threshold_code; data->temp_error1 = pdata->efuse_value;
goto out;
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);
writeb(pdata->trigger_levels[0],
data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0);
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,
data->base + EXYNOS_TMU_REG_INTCLEAR);
} else if (data->soc == SOC_ARCH_EXYNOS) {
/* Write temperature code for threshold */
threshold_code = temp_to_code(data, pdata->trigger_levels[0]);
if (threshold_code < 0) {
ret = threshold_code;
goto out;
}
rising_threshold = threshold_code;
threshold_code = temp_to_code(data, pdata->trigger_levels[1]);
if (threshold_code < 0) {
ret = threshold_code;
goto out;
}
rising_threshold |= (threshold_code << 8);
threshold_code = temp_to_code(data, pdata->trigger_levels[2]);
if (threshold_code < 0) {
ret = threshold_code;
goto out;
}
rising_threshold |= (threshold_code << 16);
writel(rising_threshold,
data->base + EXYNOS_THD_TEMP_RISE);
writel(0, data->base + EXYNOS_THD_TEMP_FALL);
writel(EXYNOS_TMU_CLEAR_RISE_INT|EXYNOS_TMU_CLEAR_FALL_INT,
data->base + EXYNOS_TMU_REG_INTCLEAR);
} }
writeb(threshold_code,
data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
writeb(pdata->trigger_levels[0],
data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
writeb(pdata->trigger_levels[1],
data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
writeb(pdata->trigger_levels[2],
data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
writeb(pdata->trigger_levels[3],
data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
writel(EXYNOS4_TMU_INTCLEAR_VAL,
data->base + EXYNOS4_TMU_REG_INTCLEAR);
out: out:
clk_disable(data->clk); clk_disable(data->clk);
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
...@@ -188,35 +267,41 @@ static int exynos4_tmu_initialize(struct platform_device *pdev) ...@@ -188,35 +267,41 @@ static int exynos4_tmu_initialize(struct platform_device *pdev)
return ret; return ret;
} }
static void exynos4_tmu_control(struct platform_device *pdev, bool on) static void exynos_tmu_control(struct platform_device *pdev, bool on)
{ {
struct exynos4_tmu_data *data = platform_get_drvdata(pdev); struct exynos_tmu_data *data = platform_get_drvdata(pdev);
struct exynos4_tmu_platform_data *pdata = data->pdata; struct exynos_tmu_platform_data *pdata = data->pdata;
unsigned int con, interrupt_en; unsigned int con, interrupt_en;
mutex_lock(&data->lock); mutex_lock(&data->lock);
clk_enable(data->clk); clk_enable(data->clk);
con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT | con = pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT |
pdata->gain << EXYNOS4_TMU_GAIN_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) { if (on) {
con |= EXYNOS4_TMU_CORE_ON; con |= EXYNOS_TMU_CORE_ON;
interrupt_en = pdata->trigger_level3_en << 12 | interrupt_en = pdata->trigger_level3_en << 12 |
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;
} else { } else {
con |= EXYNOS4_TMU_CORE_OFF; con |= EXYNOS_TMU_CORE_OFF;
interrupt_en = 0; /* Disable all interrupts */ interrupt_en = 0; /* Disable all interrupts */
} }
writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN); writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
writel(con, data->base + EXYNOS4_TMU_REG_CONTROL); writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
clk_disable(data->clk); clk_disable(data->clk);
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
} }
static int exynos4_tmu_read(struct exynos4_tmu_data *data) static int exynos_tmu_read(struct exynos_tmu_data *data)
{ {
u8 temp_code; u8 temp_code;
int temp; int temp;
...@@ -224,7 +309,7 @@ static int exynos4_tmu_read(struct exynos4_tmu_data *data) ...@@ -224,7 +309,7 @@ static int exynos4_tmu_read(struct exynos4_tmu_data *data)
mutex_lock(&data->lock); mutex_lock(&data->lock);
clk_enable(data->clk); clk_enable(data->clk);
temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP); temp_code = readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP);
temp = code_to_temp(data, temp_code); temp = code_to_temp(data, temp_code);
clk_disable(data->clk); clk_disable(data->clk);
...@@ -233,25 +318,30 @@ static int exynos4_tmu_read(struct exynos4_tmu_data *data) ...@@ -233,25 +318,30 @@ static int exynos4_tmu_read(struct exynos4_tmu_data *data)
return temp; return temp;
} }
static void exynos4_tmu_work(struct work_struct *work) static void exynos_tmu_work(struct work_struct *work)
{ {
struct exynos4_tmu_data *data = container_of(work, struct exynos_tmu_data *data = container_of(work,
struct exynos4_tmu_data, irq_work); struct exynos_tmu_data, irq_work);
mutex_lock(&data->lock); mutex_lock(&data->lock);
clk_enable(data->clk); clk_enable(data->clk);
writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
enable_irq(data->irq); if (data->soc == SOC_ARCH_EXYNOS)
writel(EXYNOS_TMU_CLEAR_RISE_INT,
data->base + EXYNOS_TMU_REG_INTCLEAR);
else
writel(EXYNOS4210_TMU_INTCLEAR_VAL,
data->base + EXYNOS_TMU_REG_INTCLEAR);
clk_disable(data->clk); clk_disable(data->clk);
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
enable_irq(data->irq);
} }
static irqreturn_t exynos4_tmu_irq(int irq, void *id) static irqreturn_t exynos_tmu_irq(int irq, void *id)
{ {
struct exynos4_tmu_data *data = id; struct exynos_tmu_data *data = id;
disable_irq_nosync(irq); disable_irq_nosync(irq);
schedule_work(&data->irq_work); schedule_work(&data->irq_work);
...@@ -259,18 +349,17 @@ static irqreturn_t exynos4_tmu_irq(int irq, void *id) ...@@ -259,18 +349,17 @@ static irqreturn_t exynos4_tmu_irq(int irq, void *id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int __devinit exynos4_tmu_probe(struct platform_device *pdev) static int __devinit exynos_tmu_probe(struct platform_device *pdev)
{ {
struct exynos4_tmu_data *data; struct exynos_tmu_data *data;
struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data; struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
int ret; int ret;
if (!pdata) { if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n"); dev_err(&pdev->dev, "No platform init data supplied.\n");
return -ENODEV; return -ENODEV;
} }
data = kzalloc(sizeof(struct exynos_tmu_data), GFP_KERNEL);
data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
if (!data) { if (!data) {
dev_err(&pdev->dev, "Failed to allocate driver structure\n"); dev_err(&pdev->dev, "Failed to allocate driver structure\n");
return -ENOMEM; return -ENOMEM;
...@@ -283,7 +372,7 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev) ...@@ -283,7 +372,7 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
goto err_free; goto err_free;
} }
INIT_WORK(&data->irq_work, exynos4_tmu_work); INIT_WORK(&data->irq_work, exynos_tmu_work);
data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!data->mem) { if (!data->mem) {
...@@ -307,9 +396,8 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev) ...@@ -307,9 +396,8 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
goto err_mem_region; goto err_mem_region;
} }
ret = request_irq(data->irq, exynos4_tmu_irq, ret = request_irq(data->irq, exynos_tmu_irq,
IRQF_TRIGGER_RISING, IRQF_TRIGGER_RISING, "exynos-tmu", data);
"exynos4-tmu", data);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
goto err_io_remap; goto err_io_remap;
...@@ -322,17 +410,26 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev) ...@@ -322,17 +410,26 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
goto err_irq; goto err_irq;
} }
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; data->pdata = pdata;
platform_set_drvdata(pdev, data); platform_set_drvdata(pdev, data);
mutex_init(&data->lock); mutex_init(&data->lock);
ret = exynos4_tmu_initialize(pdev); ret = exynos_tmu_initialize(pdev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to initialize TMU\n"); dev_err(&pdev->dev, "Failed to initialize TMU\n");
goto err_clk; goto err_clk;
} }
exynos4_tmu_control(pdev, true); exynos_tmu_control(pdev, true);
return 0; return 0;
err_clk: err_clk:
...@@ -350,11 +447,11 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev) ...@@ -350,11 +447,11 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int __devexit exynos4_tmu_remove(struct platform_device *pdev) static int __devexit exynos_tmu_remove(struct platform_device *pdev)
{ {
struct exynos4_tmu_data *data = platform_get_drvdata(pdev); struct exynos_tmu_data *data = platform_get_drvdata(pdev);
exynos4_tmu_control(pdev, false); exynos_tmu_control(pdev, false);
clk_put(data->clk); clk_put(data->clk);
...@@ -371,43 +468,43 @@ static int __devexit exynos4_tmu_remove(struct platform_device *pdev) ...@@ -371,43 +468,43 @@ static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int exynos4_tmu_suspend(struct device *dev) static int exynos_tmu_suspend(struct device *dev)
{ {
exynos4_tmu_control(to_platform_device(dev), false); exynos_tmu_control(to_platform_device(dev), false);
return 0; return 0;
} }
static int exynos4_tmu_resume(struct device *dev) static int exynos_tmu_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
exynos4_tmu_initialize(pdev); exynos_tmu_initialize(pdev);
exynos4_tmu_control(pdev, true); exynos_tmu_control(pdev, true);
return 0; return 0;
} }
static SIMPLE_DEV_PM_OPS(exynos4_tmu_pm, static SIMPLE_DEV_PM_OPS(exynos_tmu_pm,
exynos4_tmu_suspend, exynos4_tmu_resume); exynos_tmu_suspend, exynos_tmu_resume);
#define EXYNOS4_TMU_PM (&exynos4_tmu_pm) #define EXYNOS_TMU_PM (&exynos_tmu_pm)
#else #else
#define EXYNOS4_TMU_PM NULL #define EXYNOS_TMU_PM NULL
#endif #endif
static struct platform_driver exynos4_tmu_driver = { static struct platform_driver exynos_tmu_driver = {
.driver = { .driver = {
.name = "exynos4-tmu", .name = "exynos-tmu",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = EXYNOS4_TMU_PM, .pm = EXYNOS_TMU_PM,
}, },
.probe = exynos4_tmu_probe, .probe = exynos_tmu_probe,
.remove = __devexit_p(exynos4_tmu_remove), .remove = __devexit_p(exynos_tmu_remove),
}; };
module_platform_driver(exynos4_tmu_driver); module_platform_driver(exynos_tmu_driver);
MODULE_DESCRIPTION("EXYNOS4 TMU Driver"); MODULE_DESCRIPTION("EXYNOS TMU Driver");
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:exynos4-tmu"); MODULE_ALIAS("platform:exynos-tmu");
/* /*
* exynos_thermal.h - Samsung EXYNOS4 TMU (Thermal Management Unit) * exynos_thermal.h - Samsung EXYNOS TMU (Thermal Management Unit)
* *
* Copyright (C) 2011 Samsung Electronics * Copyright (C) 2011 Samsung Electronics
* Donggeun Kim <dg77.kim@samsung.com> * Donggeun Kim <dg77.kim@samsung.com>
...@@ -28,8 +28,12 @@ enum calibration_type { ...@@ -28,8 +28,12 @@ enum calibration_type {
TYPE_NONE, TYPE_NONE,
}; };
enum soc_type {
SOC_ARCH_EXYNOS4210 = 1,
SOC_ARCH_EXYNOS,
};
/** /**
* struct exynos4_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]
* @trigger_levels: array for each interrupt levels * @trigger_levels: array for each interrupt levels
...@@ -63,11 +67,15 @@ enum calibration_type { ...@@ -63,11 +67,15 @@ enum calibration_type {
* @reference_voltage: reference voltage of amplifier * @reference_voltage: reference voltage of amplifier
* in the positive-TC generator block * in the positive-TC generator block
* 0 <= reference_voltage <= 31 * 0 <= reference_voltage <= 31
* @noise_cancel_mode: noise cancellation mode
* 000, 100, 101, 110 and 111 can be different modes
* @type: determines the type of SOC
* @efuse_value: platform defined fuse value
* @cal_type: calibration type for temperature * @cal_type: calibration type for temperature
* *
* This structure is required for configuration of exynos4_tmu driver. * This structure is required for configuration of exynos_tmu driver.
*/ */
struct exynos4_tmu_platform_data { struct exynos_tmu_platform_data {
u8 threshold; u8 threshold;
u8 trigger_levels[4]; u8 trigger_levels[4];
bool trigger_level0_en; bool trigger_level0_en;
...@@ -77,7 +85,10 @@ struct exynos4_tmu_platform_data { ...@@ -77,7 +85,10 @@ struct exynos4_tmu_platform_data {
u8 gain; u8 gain;
u8 reference_voltage; u8 reference_voltage;
u8 noise_cancel_mode;
u32 efuse_value;
enum calibration_type cal_type; enum calibration_type cal_type;
enum soc_type type;
}; };
#endif /* _LINUX_EXYNOS_THERMAL_H */ #endif /* _LINUX_EXYNOS_THERMAL_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册