2 * exynos_thermal.c - Samsung EXYNOS TMU (Thermal Management Unit)
4 * Copyright (C) 2011 Samsung Electronics
5 * Donggeun Kim <dg77.kim@samsung.com>
6 * Amit Daniel Kachhap <amit.kachhap@linaro.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <linux/module.h>
25 #include <linux/err.h>
26 #include <linux/kernel.h>
27 #include <linux/slab.h>
28 #include <linux/platform_device.h>
29 #include <linux/interrupt.h>
30 #include <linux/clk.h>
31 #include <linux/workqueue.h>
32 #include <linux/sysfs.h>
33 #include <linux/kobject.h>
35 #include <linux/mutex.h>
37 #include <linux/platform_data/exynos_thermal.h>
39 #define EXYNOS4_TMU_REG_TRIMINFO 0x0
40 #define EXYNOS4_TMU_REG_CONTROL 0x20
41 #define EXYNOS4_TMU_REG_STATUS 0x28
42 #define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40
43 #define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44
44 #define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50
45 #define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54
46 #define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58
47 #define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C
48 #define EXYNOS4_TMU_REG_PAST_TEMP0 0x60
49 #define EXYNOS4_TMU_REG_PAST_TEMP1 0x64
50 #define EXYNOS4_TMU_REG_PAST_TEMP2 0x68
51 #define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C
52 #define EXYNOS4_TMU_REG_INTEN 0x70
53 #define EXYNOS4_TMU_REG_INTSTAT 0x74
54 #define EXYNOS4_TMU_REG_INTCLEAR 0x78
56 #define EXYNOS4_TMU_GAIN_SHIFT 8
57 #define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24
59 #define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff
60 #define EXYNOS4_TMU_CORE_ON 3
61 #define EXYNOS4_TMU_CORE_OFF 2
62 #define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50
63 #define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1
64 #define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10
65 #define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100
66 #define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
67 #define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
69 struct exynos4_tmu_data {
70 struct exynos4_tmu_platform_data *pdata;
74 struct work_struct irq_work;
77 u8 temp_error1, temp_error2;
81 * TMU treats temperature as a mapped temperature code.
82 * The temperature is converted differently depending on the calibration type.
84 static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
86 struct exynos4_tmu_platform_data *pdata = data->pdata;
89 /* temp should range between 25 and 125 */
90 if (temp < 25 || temp > 125) {
95 switch (pdata->cal_type) {
96 case TYPE_TWO_POINT_TRIMMING:
97 temp_code = (temp - 25) *
98 (data->temp_error2 - data->temp_error1) /
99 (85 - 25) + data->temp_error1;
101 case TYPE_ONE_POINT_TRIMMING:
102 temp_code = temp + data->temp_error1 - 25;
105 temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
113 * Calculate a temperature value from a temperature code.
114 * The unit of the temperature is degree Celsius.
116 static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
118 struct exynos4_tmu_platform_data *pdata = data->pdata;
121 /* temp_code should range between 75 and 175 */
122 if (temp_code < 75 || temp_code > 175) {
127 switch (pdata->cal_type) {
128 case TYPE_TWO_POINT_TRIMMING:
129 temp = (temp_code - data->temp_error1) * (85 - 25) /
130 (data->temp_error2 - data->temp_error1) + 25;
132 case TYPE_ONE_POINT_TRIMMING:
133 temp = temp_code - data->temp_error1 + 25;
136 temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
143 static int exynos4_tmu_initialize(struct platform_device *pdev)
145 struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
146 struct exynos4_tmu_platform_data *pdata = data->pdata;
147 unsigned int status, trim_info;
148 int ret = 0, threshold_code;
150 mutex_lock(&data->lock);
151 clk_enable(data->clk);
153 status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
159 /* Save trimming info in order to perform calibration */
160 trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
161 data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
162 data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);
164 /* Write temperature code for threshold */
165 threshold_code = temp_to_code(data, pdata->threshold);
166 if (threshold_code < 0) {
167 ret = threshold_code;
170 writeb(threshold_code,
171 data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
173 writeb(pdata->trigger_levels[0],
174 data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
175 writeb(pdata->trigger_levels[1],
176 data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
177 writeb(pdata->trigger_levels[2],
178 data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
179 writeb(pdata->trigger_levels[3],
180 data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
182 writel(EXYNOS4_TMU_INTCLEAR_VAL,
183 data->base + EXYNOS4_TMU_REG_INTCLEAR);
185 clk_disable(data->clk);
186 mutex_unlock(&data->lock);
191 static void exynos4_tmu_control(struct platform_device *pdev, bool on)
193 struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
194 struct exynos4_tmu_platform_data *pdata = data->pdata;
195 unsigned int con, interrupt_en;
197 mutex_lock(&data->lock);
198 clk_enable(data->clk);
200 con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT |
201 pdata->gain << EXYNOS4_TMU_GAIN_SHIFT;
203 con |= EXYNOS4_TMU_CORE_ON;
204 interrupt_en = pdata->trigger_level3_en << 12 |
205 pdata->trigger_level2_en << 8 |
206 pdata->trigger_level1_en << 4 |
207 pdata->trigger_level0_en;
209 con |= EXYNOS4_TMU_CORE_OFF;
210 interrupt_en = 0; /* Disable all interrupts */
212 writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN);
213 writel(con, data->base + EXYNOS4_TMU_REG_CONTROL);
215 clk_disable(data->clk);
216 mutex_unlock(&data->lock);
219 static int exynos4_tmu_read(struct exynos4_tmu_data *data)
224 mutex_lock(&data->lock);
225 clk_enable(data->clk);
227 temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP);
228 temp = code_to_temp(data, temp_code);
230 clk_disable(data->clk);
231 mutex_unlock(&data->lock);
236 static void exynos4_tmu_work(struct work_struct *work)
238 struct exynos4_tmu_data *data = container_of(work,
239 struct exynos4_tmu_data, irq_work);
241 mutex_lock(&data->lock);
242 clk_enable(data->clk);
244 writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
246 enable_irq(data->irq);
248 clk_disable(data->clk);
249 mutex_unlock(&data->lock);
252 static irqreturn_t exynos4_tmu_irq(int irq, void *id)
254 struct exynos4_tmu_data *data = id;
256 disable_irq_nosync(irq);
257 schedule_work(&data->irq_work);
262 static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
264 struct exynos4_tmu_data *data;
265 struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
269 dev_err(&pdev->dev, "No platform init data supplied.\n");
273 data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
275 dev_err(&pdev->dev, "Failed to allocate driver structure\n");
279 data->irq = platform_get_irq(pdev, 0);
282 dev_err(&pdev->dev, "Failed to get platform irq\n");
286 INIT_WORK(&data->irq_work, exynos4_tmu_work);
288 data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
291 dev_err(&pdev->dev, "Failed to get platform resource\n");
295 data->mem = request_mem_region(data->mem->start,
296 resource_size(data->mem), pdev->name);
299 dev_err(&pdev->dev, "Failed to request memory region\n");
303 data->base = ioremap(data->mem->start, resource_size(data->mem));
306 dev_err(&pdev->dev, "Failed to ioremap memory\n");
310 ret = request_irq(data->irq, exynos4_tmu_irq,
312 "exynos4-tmu", data);
314 dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
318 data->clk = clk_get(NULL, "tmu_apbif");
319 if (IS_ERR(data->clk)) {
320 ret = PTR_ERR(data->clk);
321 dev_err(&pdev->dev, "Failed to get clock\n");
326 platform_set_drvdata(pdev, data);
327 mutex_init(&data->lock);
329 ret = exynos4_tmu_initialize(pdev);
331 dev_err(&pdev->dev, "Failed to initialize TMU\n");
335 exynos4_tmu_control(pdev, true);
339 platform_set_drvdata(pdev, NULL);
342 free_irq(data->irq, data);
346 release_mem_region(data->mem->start, resource_size(data->mem));
353 static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
355 struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
357 exynos4_tmu_control(pdev, false);
361 free_irq(data->irq, data);
364 release_mem_region(data->mem->start, resource_size(data->mem));
366 platform_set_drvdata(pdev, NULL);
373 #ifdef CONFIG_PM_SLEEP
374 static int exynos4_tmu_suspend(struct device *dev)
376 exynos4_tmu_control(to_platform_device(dev), false);
381 static int exynos4_tmu_resume(struct device *dev)
383 struct platform_device *pdev = to_platform_device(dev);
385 exynos4_tmu_initialize(pdev);
386 exynos4_tmu_control(pdev, true);
391 static SIMPLE_DEV_PM_OPS(exynos4_tmu_pm,
392 exynos4_tmu_suspend, exynos4_tmu_resume);
393 #define EXYNOS4_TMU_PM (&exynos4_tmu_pm)
395 #define EXYNOS4_TMU_PM NULL
398 static struct platform_driver exynos4_tmu_driver = {
400 .name = "exynos4-tmu",
401 .owner = THIS_MODULE,
402 .pm = EXYNOS4_TMU_PM,
404 .probe = exynos4_tmu_probe,
405 .remove = __devexit_p(exynos4_tmu_remove),
408 module_platform_driver(exynos4_tmu_driver);
410 MODULE_DESCRIPTION("EXYNOS4 TMU Driver");
411 MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
412 MODULE_LICENSE("GPL");
413 MODULE_ALIAS("platform:exynos4-tmu");