diff options
author | Amit Daniel Kachhap <amit.daniel@samsung.com> | 2013-06-24 06:50:43 -0400 |
---|---|---|
committer | Eduardo Valentin <eduardo.valentin@ti.com> | 2013-08-13 09:52:03 -0400 |
commit | a0395eee7ca19623f69f067cc8cfbd4385d85dad (patch) | |
tree | 4134b00db51d7af53b7257334db9f376fdf083ea | |
parent | d9b6ee148dadd85433803f25cc62024ffcb4a0b8 (diff) |
thermal: exynos: Add driver support for exynos5440 TMU sensor
This patch modifies TMU controller to add changes needed to work with
exynos5440 platform. This sensor registers 3 instance of the tmu controller
with the thermal zone and hence reports 3 temperature output. This controller
supports upto five trip points. For critical threshold the driver uses the
core driver thermal framework for shutdown.
Acked-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
Acked-by: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Jungseok Lee <jays.lee@samsung.com>
Signed-off-by: Amit Daniel Kachhap <amit.daniel@samsung.com>
Acked-by: Eduardo Valentin <eduardo.valentin@ti.com>
Signed-off-by: Eduardo Valentin <eduardo.valentin@ti.com>
-rw-r--r-- | drivers/thermal/samsung/exynos_thermal_common.h | 2 | ||||
-rw-r--r-- | drivers/thermal/samsung/exynos_tmu.c | 55 | ||||
-rw-r--r-- | drivers/thermal/samsung/exynos_tmu.h | 6 | ||||
-rw-r--r-- | drivers/thermal/samsung/exynos_tmu_data.h | 36 |
4 files changed, 90 insertions, 9 deletions
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h index bc3016e6e9d6..3eb2ed9ea3a4 100644 --- a/drivers/thermal/samsung/exynos_thermal_common.h +++ b/drivers/thermal/samsung/exynos_thermal_common.h | |||
@@ -27,7 +27,7 @@ | |||
27 | #define SENSOR_NAME_LEN 16 | 27 | #define SENSOR_NAME_LEN 16 |
28 | #define MAX_TRIP_COUNT 8 | 28 | #define MAX_TRIP_COUNT 8 |
29 | #define MAX_COOLING_DEVICE 4 | 29 | #define MAX_COOLING_DEVICE 4 |
30 | #define MAX_THRESHOLD_LEVS 4 | 30 | #define MAX_THRESHOLD_LEVS 5 |
31 | 31 | ||
32 | #define ACTIVE_INTERVAL 500 | 32 | #define ACTIVE_INTERVAL 500 |
33 | #define IDLE_INTERVAL 10000 | 33 | #define IDLE_INTERVAL 10000 |
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 31bf373734bb..6bc86f6f91e9 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c | |||
@@ -156,7 +156,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev) | |||
156 | __raw_writel(1, data->base + reg->triminfo_ctrl); | 156 | __raw_writel(1, data->base + reg->triminfo_ctrl); |
157 | 157 | ||
158 | /* Save trimming info in order to perform calibration */ | 158 | /* Save trimming info in order to perform calibration */ |
159 | trim_info = readl(data->base + reg->triminfo_data); | 159 | if (data->soc == SOC_ARCH_EXYNOS5440) { |
160 | /* | ||
161 | * For exynos5440 soc triminfo value is swapped between TMU0 and | ||
162 | * TMU2, so the below logic is needed. | ||
163 | */ | ||
164 | switch (data->id) { | ||
165 | case 0: | ||
166 | trim_info = readl(data->base + | ||
167 | EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data); | ||
168 | break; | ||
169 | case 1: | ||
170 | trim_info = readl(data->base + reg->triminfo_data); | ||
171 | break; | ||
172 | case 2: | ||
173 | trim_info = readl(data->base - | ||
174 | EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data); | ||
175 | } | ||
176 | } else { | ||
177 | trim_info = readl(data->base + reg->triminfo_data); | ||
178 | } | ||
160 | data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK; | 179 | data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK; |
161 | data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) & | 180 | data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) & |
162 | EXYNOS_TMU_TEMP_MASK); | 181 | EXYNOS_TMU_TEMP_MASK); |
@@ -201,7 +220,7 @@ static int exynos_tmu_initialize(struct platform_device *pdev) | |||
201 | reg->threshold_th0 + i * sizeof(reg->threshold_th0)); | 220 | reg->threshold_th0 + i * sizeof(reg->threshold_th0)); |
202 | 221 | ||
203 | writel(reg->inten_rise_mask, data->base + reg->tmu_intclear); | 222 | writel(reg->inten_rise_mask, data->base + reg->tmu_intclear); |
204 | } else if (data->soc == SOC_ARCH_EXYNOS) { | 223 | } else { |
205 | /* Write temperature code for rising and falling threshold */ | 224 | /* Write temperature code for rising and falling threshold */ |
206 | for (i = 0; | 225 | for (i = 0; |
207 | i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) { | 226 | i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) { |
@@ -241,14 +260,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev) | |||
241 | ret = threshold_code; | 260 | ret = threshold_code; |
242 | goto out; | 261 | goto out; |
243 | } | 262 | } |
244 | rising_threshold |= threshold_code << 8 * i; | 263 | if (i == EXYNOS_MAX_TRIGGER_PER_REG - 1) { |
245 | writel(rising_threshold, | 264 | /* 1-4 level to be assigned in th0 reg */ |
246 | data->base + reg->threshold_th0); | 265 | rising_threshold |= threshold_code << 8 * i; |
266 | writel(rising_threshold, | ||
267 | data->base + reg->threshold_th0); | ||
268 | } else if (i == EXYNOS_MAX_TRIGGER_PER_REG) { | ||
269 | /* 5th level to be assigned in th2 reg */ | ||
270 | rising_threshold = | ||
271 | threshold_code << reg->threshold_th3_l0_shift; | ||
272 | writel(rising_threshold, | ||
273 | data->base + reg->threshold_th2); | ||
274 | } | ||
247 | con = readl(data->base + reg->tmu_ctrl); | 275 | con = readl(data->base + reg->tmu_ctrl); |
248 | con |= (1 << reg->therm_trip_en_shift); | 276 | con |= (1 << reg->therm_trip_en_shift); |
249 | writel(con, data->base + reg->tmu_ctrl); | 277 | writel(con, data->base + reg->tmu_ctrl); |
250 | } | 278 | } |
251 | } | 279 | } |
280 | /*Clear the PMIN in the common TMU register*/ | ||
281 | if (reg->tmu_pmin && !data->id) | ||
282 | writel(0, data->base_common + reg->tmu_pmin); | ||
252 | out: | 283 | out: |
253 | clk_disable(data->clk); | 284 | clk_disable(data->clk); |
254 | mutex_unlock(&data->lock); | 285 | mutex_unlock(&data->lock); |
@@ -377,7 +408,14 @@ static void exynos_tmu_work(struct work_struct *work) | |||
377 | struct exynos_tmu_data, irq_work); | 408 | struct exynos_tmu_data, irq_work); |
378 | struct exynos_tmu_platform_data *pdata = data->pdata; | 409 | struct exynos_tmu_platform_data *pdata = data->pdata; |
379 | const struct exynos_tmu_registers *reg = pdata->registers; | 410 | const struct exynos_tmu_registers *reg = pdata->registers; |
380 | unsigned int val_irq; | 411 | unsigned int val_irq, val_type; |
412 | |||
413 | /* Find which sensor generated this interrupt */ | ||
414 | if (reg->tmu_irqstatus) { | ||
415 | val_type = readl(data->base_common + reg->tmu_irqstatus); | ||
416 | if (!((val_type >> data->id) & 0x1)) | ||
417 | goto out; | ||
418 | } | ||
381 | 419 | ||
382 | exynos_report_trigger(data->reg_conf); | 420 | exynos_report_trigger(data->reg_conf); |
383 | mutex_lock(&data->lock); | 421 | mutex_lock(&data->lock); |
@@ -390,7 +428,7 @@ static void exynos_tmu_work(struct work_struct *work) | |||
390 | 428 | ||
391 | clk_disable(data->clk); | 429 | clk_disable(data->clk); |
392 | mutex_unlock(&data->lock); | 430 | mutex_unlock(&data->lock); |
393 | 431 | out: | |
394 | enable_irq(data->irq); | 432 | enable_irq(data->irq); |
395 | } | 433 | } |
396 | 434 | ||
@@ -538,7 +576,8 @@ static int exynos_tmu_probe(struct platform_device *pdev) | |||
538 | return ret; | 576 | return ret; |
539 | 577 | ||
540 | if (pdata->type == SOC_ARCH_EXYNOS || | 578 | if (pdata->type == SOC_ARCH_EXYNOS || |
541 | pdata->type == SOC_ARCH_EXYNOS4210) | 579 | pdata->type == SOC_ARCH_EXYNOS4210 || |
580 | pdata->type == SOC_ARCH_EXYNOS5440) | ||
542 | data->soc = pdata->type; | 581 | data->soc = pdata->type; |
543 | else { | 582 | else { |
544 | ret = -EINVAL; | 583 | ret = -EINVAL; |
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h index ff8844f3b99b..25c48d49ad47 100644 --- a/drivers/thermal/samsung/exynos_tmu.h +++ b/drivers/thermal/samsung/exynos_tmu.h | |||
@@ -40,6 +40,7 @@ enum calibration_mode { | |||
40 | enum soc_type { | 40 | enum soc_type { |
41 | SOC_ARCH_EXYNOS4210 = 1, | 41 | SOC_ARCH_EXYNOS4210 = 1, |
42 | SOC_ARCH_EXYNOS, | 42 | SOC_ARCH_EXYNOS, |
43 | SOC_ARCH_EXYNOS5440, | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | /** | 46 | /** |
@@ -131,6 +132,8 @@ enum soc_type { | |||
131 | * @emul_temp_shift: shift bits of emulation temperature. | 132 | * @emul_temp_shift: shift bits of emulation temperature. |
132 | * @emul_time_shift: shift bits of emulation time. | 133 | * @emul_time_shift: shift bits of emulation time. |
133 | * @emul_time_mask: mask bits of emulation time. | 134 | * @emul_time_mask: mask bits of emulation time. |
135 | * @tmu_irqstatus: register to find which TMU generated interrupts. | ||
136 | * @tmu_pmin: register to get/set the Pmin value. | ||
134 | */ | 137 | */ |
135 | struct exynos_tmu_registers { | 138 | struct exynos_tmu_registers { |
136 | u32 triminfo_data; | 139 | u32 triminfo_data; |
@@ -198,6 +201,9 @@ struct exynos_tmu_registers { | |||
198 | u32 emul_temp_shift; | 201 | u32 emul_temp_shift; |
199 | u32 emul_time_shift; | 202 | u32 emul_time_shift; |
200 | u32 emul_time_mask; | 203 | u32 emul_time_mask; |
204 | |||
205 | u32 tmu_irqstatus; | ||
206 | u32 tmu_pmin; | ||
201 | }; | 207 | }; |
202 | 208 | ||
203 | /** | 209 | /** |
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h index 139dbbb1e264..ad263e9bb58f 100644 --- a/drivers/thermal/samsung/exynos_tmu_data.h +++ b/drivers/thermal/samsung/exynos_tmu_data.h | |||
@@ -93,6 +93,42 @@ | |||
93 | 93 | ||
94 | #define EXYNOS_MAX_TRIGGER_PER_REG 4 | 94 | #define EXYNOS_MAX_TRIGGER_PER_REG 4 |
95 | 95 | ||
96 | /*exynos5440 specific registers*/ | ||
97 | #define EXYNOS5440_TMU_S0_7_TRIM 0x000 | ||
98 | #define EXYNOS5440_TMU_S0_7_CTRL 0x020 | ||
99 | #define EXYNOS5440_TMU_S0_7_DEBUG 0x040 | ||
100 | #define EXYNOS5440_TMU_S0_7_STATUS 0x060 | ||
101 | #define EXYNOS5440_TMU_S0_7_TEMP 0x0f0 | ||
102 | #define EXYNOS5440_TMU_S0_7_TH0 0x110 | ||
103 | #define EXYNOS5440_TMU_S0_7_TH1 0x130 | ||
104 | #define EXYNOS5440_TMU_S0_7_TH2 0x150 | ||
105 | #define EXYNOS5440_TMU_S0_7_EVTEN 0x1F0 | ||
106 | #define EXYNOS5440_TMU_S0_7_IRQEN 0x210 | ||
107 | #define EXYNOS5440_TMU_S0_7_IRQ 0x230 | ||
108 | /* exynos5440 common registers */ | ||
109 | #define EXYNOS5440_TMU_IRQ_STATUS 0x000 | ||
110 | #define EXYNOS5440_TMU_PMIN 0x004 | ||
111 | #define EXYNOS5440_TMU_TEMP 0x008 | ||
112 | |||
113 | #define EXYNOS5440_TMU_RISE_INT_MASK 0xf | ||
114 | #define EXYNOS5440_TMU_RISE_INT_SHIFT 0 | ||
115 | #define EXYNOS5440_TMU_FALL_INT_MASK 0xf | ||
116 | #define EXYNOS5440_TMU_FALL_INT_SHIFT 4 | ||
117 | #define EXYNOS5440_TMU_INTEN_RISE0_SHIFT 0 | ||
118 | #define EXYNOS5440_TMU_INTEN_RISE1_SHIFT 1 | ||
119 | #define EXYNOS5440_TMU_INTEN_RISE2_SHIFT 2 | ||
120 | #define EXYNOS5440_TMU_INTEN_RISE3_SHIFT 3 | ||
121 | #define EXYNOS5440_TMU_INTEN_FALL0_SHIFT 4 | ||
122 | #define EXYNOS5440_TMU_INTEN_FALL1_SHIFT 5 | ||
123 | #define EXYNOS5440_TMU_INTEN_FALL2_SHIFT 6 | ||
124 | #define EXYNOS5440_TMU_INTEN_FALL3_SHIFT 7 | ||
125 | #define EXYNOS5440_TMU_TH_RISE0_SHIFT 0 | ||
126 | #define EXYNOS5440_TMU_TH_RISE1_SHIFT 8 | ||
127 | #define EXYNOS5440_TMU_TH_RISE2_SHIFT 16 | ||
128 | #define EXYNOS5440_TMU_TH_RISE3_SHIFT 24 | ||
129 | #define EXYNOS5440_TMU_TH_RISE4_SHIFT 24 | ||
130 | #define EXYNOS5440_EFUSE_SWAP_OFFSET 8 | ||
131 | |||
96 | #if defined(CONFIG_CPU_EXYNOS4210) | 132 | #if defined(CONFIG_CPU_EXYNOS4210) |
97 | extern struct exynos_tmu_init_data const exynos4210_default_tmu_data; | 133 | extern struct exynos_tmu_init_data const exynos4210_default_tmu_data; |
98 | #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data) | 134 | #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data) |