1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * exynos_tmu.c - Samsung Exynos TMU (Thermal Management Unit) |
4 | * |
5 | * Copyright (C) 2014 Samsung Electronics |
6 | * Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> |
7 | * Lukasz Majewski <l.majewski@samsung.com> |
8 | * |
9 | * Copyright (C) 2011 Samsung Electronics |
10 | * Donggeun Kim <dg77.kim@samsung.com> |
11 | * Amit Daniel Kachhap <amit.kachhap@linaro.org> |
12 | */ |
13 | |
14 | #include <linux/clk.h> |
15 | #include <linux/io.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/module.h> |
18 | #include <linux/of.h> |
19 | #include <linux/of_address.h> |
20 | #include <linux/of_irq.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/regulator/consumer.h> |
23 | #include <linux/thermal.h> |
24 | |
25 | #include <dt-bindings/thermal/thermal_exynos.h> |
26 | |
27 | /* Exynos generic registers */ |
28 | #define EXYNOS_TMU_REG_TRIMINFO 0x0 |
29 | #define EXYNOS_TMU_REG_CONTROL 0x20 |
30 | #define EXYNOS_TMU_REG_STATUS 0x28 |
31 | #define EXYNOS_TMU_REG_CURRENT_TEMP 0x40 |
32 | #define EXYNOS_TMU_REG_INTEN 0x70 |
33 | #define EXYNOS_TMU_REG_INTSTAT 0x74 |
34 | #define EXYNOS_TMU_REG_INTCLEAR 0x78 |
35 | |
36 | #define EXYNOS_TMU_TEMP_MASK 0xff |
37 | #define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24 |
38 | #define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f |
39 | #define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf |
40 | #define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8 |
41 | #define EXYNOS_TMU_CORE_EN_SHIFT 0 |
42 | |
43 | /* Exynos3250 specific registers */ |
44 | #define EXYNOS_TMU_TRIMINFO_CON1 0x10 |
45 | |
46 | /* Exynos4210 specific registers */ |
47 | #define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44 |
48 | #define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50 |
49 | |
50 | /* Exynos5250, Exynos4412, Exynos3250 specific registers */ |
51 | #define EXYNOS_TMU_TRIMINFO_CON2 0x14 |
52 | #define EXYNOS_THD_TEMP_RISE 0x50 |
53 | #define EXYNOS_THD_TEMP_FALL 0x54 |
54 | #define EXYNOS_EMUL_CON 0x80 |
55 | |
56 | #define EXYNOS_TRIMINFO_RELOAD_ENABLE 1 |
57 | #define EXYNOS_TRIMINFO_25_SHIFT 0 |
58 | #define EXYNOS_TRIMINFO_85_SHIFT 8 |
59 | #define EXYNOS_TMU_TRIP_MODE_SHIFT 13 |
60 | #define EXYNOS_TMU_TRIP_MODE_MASK 0x7 |
61 | #define EXYNOS_TMU_THERM_TRIP_EN_SHIFT 12 |
62 | |
63 | #define EXYNOS_TMU_INTEN_RISE0_SHIFT 0 |
64 | #define EXYNOS_TMU_INTEN_FALL0_SHIFT 16 |
65 | |
66 | #define EXYNOS_EMUL_TIME 0x57F0 |
67 | #define EXYNOS_EMUL_TIME_MASK 0xffff |
68 | #define EXYNOS_EMUL_TIME_SHIFT 16 |
69 | #define EXYNOS_EMUL_DATA_SHIFT 8 |
70 | #define EXYNOS_EMUL_DATA_MASK 0xFF |
71 | #define EXYNOS_EMUL_ENABLE 0x1 |
72 | |
73 | /* Exynos5260 specific */ |
74 | #define EXYNOS5260_TMU_REG_INTEN 0xC0 |
75 | #define EXYNOS5260_TMU_REG_INTSTAT 0xC4 |
76 | #define EXYNOS5260_TMU_REG_INTCLEAR 0xC8 |
77 | #define EXYNOS5260_EMUL_CON 0x100 |
78 | |
79 | /* Exynos4412 specific */ |
80 | #define EXYNOS4412_MUX_ADDR_VALUE 6 |
81 | #define EXYNOS4412_MUX_ADDR_SHIFT 20 |
82 | |
83 | /* Exynos5433 specific registers */ |
84 | #define EXYNOS5433_THD_TEMP_RISE3_0 0x050 |
85 | #define EXYNOS5433_THD_TEMP_RISE7_4 0x054 |
86 | #define EXYNOS5433_THD_TEMP_FALL3_0 0x060 |
87 | #define EXYNOS5433_THD_TEMP_FALL7_4 0x064 |
88 | #define EXYNOS5433_TMU_REG_INTEN 0x0c0 |
89 | #define EXYNOS5433_TMU_REG_INTPEND 0x0c8 |
90 | #define EXYNOS5433_TMU_EMUL_CON 0x110 |
91 | #define EXYNOS5433_TMU_PD_DET_EN 0x130 |
92 | |
93 | #define EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT 16 |
94 | #define EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT 23 |
95 | #define EXYNOS5433_TRIMINFO_SENSOR_ID_MASK \ |
96 | (0xf << EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT) |
97 | #define EXYNOS5433_TRIMINFO_CALIB_SEL_MASK BIT(23) |
98 | |
99 | #define EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING 0 |
100 | #define EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING 1 |
101 | |
102 | #define EXYNOS5433_PD_DET_EN 1 |
103 | |
104 | #define EXYNOS5433_G3D_BASE 0x10070000 |
105 | |
106 | /* Exynos7 specific registers */ |
107 | #define EXYNOS7_THD_TEMP_RISE7_6 0x50 |
108 | #define EXYNOS7_THD_TEMP_FALL7_6 0x60 |
109 | #define EXYNOS7_TMU_REG_INTEN 0x110 |
110 | #define EXYNOS7_TMU_REG_INTPEND 0x118 |
111 | #define EXYNOS7_TMU_REG_EMUL_CON 0x160 |
112 | |
113 | #define EXYNOS7_TMU_TEMP_MASK 0x1ff |
114 | #define EXYNOS7_PD_DET_EN_SHIFT 23 |
115 | #define EXYNOS7_TMU_INTEN_RISE0_SHIFT 0 |
116 | #define EXYNOS7_EMUL_DATA_SHIFT 7 |
117 | #define EXYNOS7_EMUL_DATA_MASK 0x1ff |
118 | |
119 | #define EXYNOS_FIRST_POINT_TRIM 25 |
120 | #define EXYNOS_SECOND_POINT_TRIM 85 |
121 | |
122 | #define EXYNOS_NOISE_CANCEL_MODE 4 |
123 | |
124 | #define MCELSIUS 1000 |
125 | |
126 | enum soc_type { |
127 | SOC_ARCH_EXYNOS3250 = 1, |
128 | SOC_ARCH_EXYNOS4210, |
129 | SOC_ARCH_EXYNOS4412, |
130 | SOC_ARCH_EXYNOS5250, |
131 | SOC_ARCH_EXYNOS5260, |
132 | SOC_ARCH_EXYNOS5420, |
133 | SOC_ARCH_EXYNOS5420_TRIMINFO, |
134 | SOC_ARCH_EXYNOS5433, |
135 | SOC_ARCH_EXYNOS7, |
136 | }; |
137 | |
138 | /** |
139 | * struct exynos_tmu_data : A structure to hold the private data of the TMU |
140 | * driver |
141 | * @base: base address of the single instance of the TMU controller. |
142 | * @base_second: base address of the common registers of the TMU controller. |
143 | * @irq: irq number of the TMU controller. |
144 | * @soc: id of the SOC type. |
145 | * @lock: lock to implement synchronization. |
146 | * @clk: pointer to the clock structure. |
147 | * @clk_sec: pointer to the clock structure for accessing the base_second. |
148 | * @sclk: pointer to the clock structure for accessing the tmu special clk. |
149 | * @cal_type: calibration type for temperature |
150 | * @efuse_value: SoC defined fuse value |
151 | * @min_efuse_value: minimum valid trimming data |
152 | * @max_efuse_value: maximum valid trimming data |
153 | * @temp_error1: fused value of the first point trim. |
154 | * @temp_error2: fused value of the second point trim. |
155 | * @gain: gain of amplifier in the positive-TC generator block |
156 | * 0 < gain <= 15 |
157 | * @reference_voltage: reference voltage of amplifier |
158 | * in the positive-TC generator block |
159 | * 0 < reference_voltage <= 31 |
160 | * @tzd: pointer to thermal_zone_device structure |
161 | * @enabled: current status of TMU device |
162 | * @tmu_set_low_temp: SoC specific method to set trip (falling threshold) |
163 | * @tmu_set_high_temp: SoC specific method to set trip (rising threshold) |
164 | * @tmu_set_crit_temp: SoC specific method to set critical temperature |
165 | * @tmu_disable_low: SoC specific method to disable an interrupt (falling threshold) |
166 | * @tmu_disable_high: SoC specific method to disable an interrupt (rising threshold) |
167 | * @tmu_initialize: SoC specific TMU initialization method |
168 | * @tmu_control: SoC specific TMU control method |
169 | * @tmu_read: SoC specific TMU temperature read method |
170 | * @tmu_set_emulation: SoC specific TMU emulation setting method |
171 | * @tmu_clear_irqs: SoC specific TMU interrupts clearing method |
172 | */ |
173 | struct exynos_tmu_data { |
174 | void __iomem *base; |
175 | void __iomem *base_second; |
176 | int irq; |
177 | enum soc_type soc; |
178 | struct mutex lock; |
179 | struct clk *clk, *clk_sec, *sclk; |
180 | u32 cal_type; |
181 | u32 efuse_value; |
182 | u32 min_efuse_value; |
183 | u32 max_efuse_value; |
184 | u16 temp_error1, temp_error2; |
185 | u8 gain; |
186 | u8 reference_voltage; |
187 | struct thermal_zone_device *tzd; |
188 | bool enabled; |
189 | |
190 | void (*tmu_set_low_temp)(struct exynos_tmu_data *data, u8 temp); |
191 | void (*tmu_set_high_temp)(struct exynos_tmu_data *data, u8 temp); |
192 | void (*tmu_set_crit_temp)(struct exynos_tmu_data *data, u8 temp); |
193 | void (*tmu_disable_low)(struct exynos_tmu_data *data); |
194 | void (*tmu_disable_high)(struct exynos_tmu_data *data); |
195 | void (*tmu_initialize)(struct platform_device *pdev); |
196 | void (*tmu_control)(struct platform_device *pdev, bool on); |
197 | int (*tmu_read)(struct exynos_tmu_data *data); |
198 | void (*tmu_set_emulation)(struct exynos_tmu_data *data, int temp); |
199 | void (*tmu_clear_irqs)(struct exynos_tmu_data *data); |
200 | }; |
201 | |
202 | /* |
203 | * TMU treats temperature as a mapped temperature code. |
204 | * The temperature is converted differently depending on the calibration type. |
205 | */ |
206 | static int temp_to_code(struct exynos_tmu_data *data, u8 temp) |
207 | { |
208 | if (data->cal_type == TYPE_ONE_POINT_TRIMMING) |
209 | return temp + data->temp_error1 - EXYNOS_FIRST_POINT_TRIM; |
210 | |
211 | return (temp - EXYNOS_FIRST_POINT_TRIM) * |
212 | (data->temp_error2 - data->temp_error1) / |
213 | (EXYNOS_SECOND_POINT_TRIM - EXYNOS_FIRST_POINT_TRIM) + |
214 | data->temp_error1; |
215 | } |
216 | |
217 | /* |
218 | * Calculate a temperature value from a temperature code. |
219 | * The unit of the temperature is degree Celsius. |
220 | */ |
221 | static int code_to_temp(struct exynos_tmu_data *data, u16 temp_code) |
222 | { |
223 | if (data->cal_type == TYPE_ONE_POINT_TRIMMING) |
224 | return temp_code - data->temp_error1 + EXYNOS_FIRST_POINT_TRIM; |
225 | |
226 | return (temp_code - data->temp_error1) * |
227 | (EXYNOS_SECOND_POINT_TRIM - EXYNOS_FIRST_POINT_TRIM) / |
228 | (data->temp_error2 - data->temp_error1) + |
229 | EXYNOS_FIRST_POINT_TRIM; |
230 | } |
231 | |
232 | static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info) |
233 | { |
234 | u16 tmu_temp_mask = |
235 | (data->soc == SOC_ARCH_EXYNOS7) ? EXYNOS7_TMU_TEMP_MASK |
236 | : EXYNOS_TMU_TEMP_MASK; |
237 | |
238 | data->temp_error1 = trim_info & tmu_temp_mask; |
239 | data->temp_error2 = ((trim_info >> EXYNOS_TRIMINFO_85_SHIFT) & |
240 | EXYNOS_TMU_TEMP_MASK); |
241 | |
242 | if (!data->temp_error1 || |
243 | (data->min_efuse_value > data->temp_error1) || |
244 | (data->temp_error1 > data->max_efuse_value)) |
245 | data->temp_error1 = data->efuse_value & EXYNOS_TMU_TEMP_MASK; |
246 | |
247 | if (!data->temp_error2) |
248 | data->temp_error2 = |
249 | (data->efuse_value >> EXYNOS_TRIMINFO_85_SHIFT) & |
250 | EXYNOS_TMU_TEMP_MASK; |
251 | } |
252 | |
253 | static int exynos_tmu_initialize(struct platform_device *pdev) |
254 | { |
255 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
256 | unsigned int status; |
257 | int ret = 0; |
258 | |
259 | mutex_lock(&data->lock); |
260 | clk_enable(clk: data->clk); |
261 | if (!IS_ERR(ptr: data->clk_sec)) |
262 | clk_enable(clk: data->clk_sec); |
263 | |
264 | status = readb(addr: data->base + EXYNOS_TMU_REG_STATUS); |
265 | if (!status) { |
266 | ret = -EBUSY; |
267 | } else { |
268 | data->tmu_initialize(pdev); |
269 | data->tmu_clear_irqs(data); |
270 | } |
271 | |
272 | if (!IS_ERR(ptr: data->clk_sec)) |
273 | clk_disable(clk: data->clk_sec); |
274 | clk_disable(clk: data->clk); |
275 | mutex_unlock(lock: &data->lock); |
276 | |
277 | return ret; |
278 | } |
279 | |
280 | static int exynos_thermal_zone_configure(struct platform_device *pdev) |
281 | { |
282 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
283 | struct thermal_zone_device *tzd = data->tzd; |
284 | int ret, temp; |
285 | |
286 | ret = thermal_zone_get_crit_temp(tz: tzd, temp: &temp); |
287 | if (ret) { |
288 | /* FIXME: Remove this special case */ |
289 | if (data->soc == SOC_ARCH_EXYNOS5433) |
290 | return 0; |
291 | |
292 | dev_err(&pdev->dev, |
293 | "No CRITICAL trip point defined in device tree!\n" ); |
294 | return ret; |
295 | } |
296 | |
297 | mutex_lock(&data->lock); |
298 | clk_enable(clk: data->clk); |
299 | |
300 | data->tmu_set_crit_temp(data, temp / MCELSIUS); |
301 | |
302 | clk_disable(clk: data->clk); |
303 | mutex_unlock(lock: &data->lock); |
304 | |
305 | return 0; |
306 | } |
307 | |
308 | static u32 get_con_reg(struct exynos_tmu_data *data, u32 con) |
309 | { |
310 | if (data->soc == SOC_ARCH_EXYNOS4412 || |
311 | data->soc == SOC_ARCH_EXYNOS3250) |
312 | con |= (EXYNOS4412_MUX_ADDR_VALUE << EXYNOS4412_MUX_ADDR_SHIFT); |
313 | |
314 | con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK << EXYNOS_TMU_REF_VOLTAGE_SHIFT); |
315 | con |= data->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT; |
316 | |
317 | con &= ~(EXYNOS_TMU_BUF_SLOPE_SEL_MASK << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT); |
318 | con |= (data->gain << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT); |
319 | |
320 | con &= ~(EXYNOS_TMU_TRIP_MODE_MASK << EXYNOS_TMU_TRIP_MODE_SHIFT); |
321 | con |= (EXYNOS_NOISE_CANCEL_MODE << EXYNOS_TMU_TRIP_MODE_SHIFT); |
322 | |
323 | return con; |
324 | } |
325 | |
326 | static void exynos_tmu_control(struct platform_device *pdev, bool on) |
327 | { |
328 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
329 | |
330 | mutex_lock(&data->lock); |
331 | clk_enable(clk: data->clk); |
332 | data->tmu_control(pdev, on); |
333 | data->enabled = on; |
334 | clk_disable(clk: data->clk); |
335 | mutex_unlock(lock: &data->lock); |
336 | } |
337 | |
338 | static void exynos_tmu_update_bit(struct exynos_tmu_data *data, int reg_off, |
339 | int bit_off, bool enable) |
340 | { |
341 | u32 interrupt_en; |
342 | |
343 | interrupt_en = readl(addr: data->base + reg_off); |
344 | if (enable) |
345 | interrupt_en |= BIT(bit_off); |
346 | else |
347 | interrupt_en &= ~BIT(bit_off); |
348 | writel(val: interrupt_en, addr: data->base + reg_off); |
349 | } |
350 | |
351 | static void exynos_tmu_update_temp(struct exynos_tmu_data *data, int reg_off, |
352 | int bit_off, u8 temp) |
353 | { |
354 | u16 tmu_temp_mask; |
355 | u32 th; |
356 | |
357 | tmu_temp_mask = |
358 | (data->soc == SOC_ARCH_EXYNOS7) ? EXYNOS7_TMU_TEMP_MASK |
359 | : EXYNOS_TMU_TEMP_MASK; |
360 | |
361 | th = readl(addr: data->base + reg_off); |
362 | th &= ~(tmu_temp_mask << bit_off); |
363 | th |= temp_to_code(data, temp) << bit_off; |
364 | writel(val: th, addr: data->base + reg_off); |
365 | } |
366 | |
367 | static void exynos4210_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp) |
368 | { |
369 | /* |
370 | * Failing thresholds are not supported on Exynos 4210. |
371 | * We use polling instead. |
372 | */ |
373 | } |
374 | |
375 | static void exynos4210_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp) |
376 | { |
377 | temp = temp_to_code(data, temp); |
378 | writeb(val: temp, addr: data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + 4); |
379 | exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, |
380 | EXYNOS_TMU_INTEN_RISE0_SHIFT + 4, enable: true); |
381 | } |
382 | |
383 | static void exynos4210_tmu_disable_low(struct exynos_tmu_data *data) |
384 | { |
385 | /* Again, this is handled by polling. */ |
386 | } |
387 | |
388 | static void exynos4210_tmu_disable_high(struct exynos_tmu_data *data) |
389 | { |
390 | exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, |
391 | EXYNOS_TMU_INTEN_RISE0_SHIFT + 4, enable: false); |
392 | } |
393 | |
394 | static void exynos4210_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp) |
395 | { |
396 | /* |
397 | * Hardware critical temperature handling is not supported on Exynos 4210. |
398 | * We still set the critical temperature threshold, but this is only to |
399 | * make sure it is handled as soon as possible. It is just a normal interrupt. |
400 | */ |
401 | |
402 | temp = temp_to_code(data, temp); |
403 | writeb(val: temp, addr: data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + 12); |
404 | exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, |
405 | EXYNOS_TMU_INTEN_RISE0_SHIFT + 12, enable: true); |
406 | } |
407 | |
408 | static void exynos4210_tmu_initialize(struct platform_device *pdev) |
409 | { |
410 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
411 | |
412 | sanitize_temp_error(data, readl(addr: data->base + EXYNOS_TMU_REG_TRIMINFO)); |
413 | |
414 | writeb(val: 0, addr: data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); |
415 | } |
416 | |
417 | static void exynos4412_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp) |
418 | { |
419 | exynos_tmu_update_temp(data, EXYNOS_THD_TEMP_FALL, bit_off: 0, temp); |
420 | exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, |
421 | EXYNOS_TMU_INTEN_FALL0_SHIFT, enable: true); |
422 | } |
423 | |
424 | static void exynos4412_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp) |
425 | { |
426 | exynos_tmu_update_temp(data, EXYNOS_THD_TEMP_RISE, bit_off: 8, temp); |
427 | exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, |
428 | EXYNOS_TMU_INTEN_RISE0_SHIFT + 4, enable: true); |
429 | } |
430 | |
431 | static void exynos4412_tmu_disable_low(struct exynos_tmu_data *data) |
432 | { |
433 | exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, |
434 | EXYNOS_TMU_INTEN_FALL0_SHIFT, enable: false); |
435 | } |
436 | |
437 | static void exynos4412_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp) |
438 | { |
439 | exynos_tmu_update_temp(data, EXYNOS_THD_TEMP_RISE, bit_off: 24, temp); |
440 | exynos_tmu_update_bit(data, EXYNOS_TMU_REG_CONTROL, |
441 | EXYNOS_TMU_THERM_TRIP_EN_SHIFT, enable: true); |
442 | } |
443 | |
444 | static void exynos4412_tmu_initialize(struct platform_device *pdev) |
445 | { |
446 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
447 | unsigned int trim_info, ctrl; |
448 | |
449 | if (data->soc == SOC_ARCH_EXYNOS3250 || |
450 | data->soc == SOC_ARCH_EXYNOS4412 || |
451 | data->soc == SOC_ARCH_EXYNOS5250) { |
452 | if (data->soc == SOC_ARCH_EXYNOS3250) { |
453 | ctrl = readl(addr: data->base + EXYNOS_TMU_TRIMINFO_CON1); |
454 | ctrl |= EXYNOS_TRIMINFO_RELOAD_ENABLE; |
455 | writel(val: ctrl, addr: data->base + EXYNOS_TMU_TRIMINFO_CON1); |
456 | } |
457 | ctrl = readl(addr: data->base + EXYNOS_TMU_TRIMINFO_CON2); |
458 | ctrl |= EXYNOS_TRIMINFO_RELOAD_ENABLE; |
459 | writel(val: ctrl, addr: data->base + EXYNOS_TMU_TRIMINFO_CON2); |
460 | } |
461 | |
462 | /* On exynos5420 the triminfo register is in the shared space */ |
463 | if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) |
464 | trim_info = readl(addr: data->base_second + EXYNOS_TMU_REG_TRIMINFO); |
465 | else |
466 | trim_info = readl(addr: data->base + EXYNOS_TMU_REG_TRIMINFO); |
467 | |
468 | sanitize_temp_error(data, trim_info); |
469 | } |
470 | |
471 | static void exynos5433_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp) |
472 | { |
473 | exynos_tmu_update_temp(data, EXYNOS5433_THD_TEMP_FALL3_0, bit_off: 0, temp); |
474 | exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN, |
475 | EXYNOS_TMU_INTEN_FALL0_SHIFT, enable: true); |
476 | } |
477 | |
478 | static void exynos5433_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp) |
479 | { |
480 | exynos_tmu_update_temp(data, EXYNOS5433_THD_TEMP_RISE3_0, bit_off: 8, temp); |
481 | exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN, |
482 | EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, enable: true); |
483 | } |
484 | |
485 | static void exynos5433_tmu_disable_low(struct exynos_tmu_data *data) |
486 | { |
487 | exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN, |
488 | EXYNOS_TMU_INTEN_FALL0_SHIFT, enable: false); |
489 | } |
490 | |
491 | static void exynos5433_tmu_disable_high(struct exynos_tmu_data *data) |
492 | { |
493 | exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN, |
494 | EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, enable: false); |
495 | } |
496 | |
497 | static void exynos5433_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp) |
498 | { |
499 | exynos_tmu_update_temp(data, EXYNOS5433_THD_TEMP_RISE7_4, bit_off: 24, temp); |
500 | exynos_tmu_update_bit(data, EXYNOS_TMU_REG_CONTROL, |
501 | EXYNOS_TMU_THERM_TRIP_EN_SHIFT, enable: true); |
502 | exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN, |
503 | EXYNOS7_TMU_INTEN_RISE0_SHIFT + 7, enable: true); |
504 | } |
505 | |
506 | static void exynos5433_tmu_initialize(struct platform_device *pdev) |
507 | { |
508 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
509 | unsigned int trim_info; |
510 | int sensor_id, cal_type; |
511 | |
512 | trim_info = readl(addr: data->base + EXYNOS_TMU_REG_TRIMINFO); |
513 | sanitize_temp_error(data, trim_info); |
514 | |
515 | /* Read the temperature sensor id */ |
516 | sensor_id = (trim_info & EXYNOS5433_TRIMINFO_SENSOR_ID_MASK) |
517 | >> EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT; |
518 | dev_info(&pdev->dev, "Temperature sensor ID: 0x%x\n" , sensor_id); |
519 | |
520 | /* Read the calibration mode */ |
521 | writel(val: trim_info, addr: data->base + EXYNOS_TMU_REG_TRIMINFO); |
522 | cal_type = (trim_info & EXYNOS5433_TRIMINFO_CALIB_SEL_MASK) |
523 | >> EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT; |
524 | |
525 | switch (cal_type) { |
526 | case EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING: |
527 | data->cal_type = TYPE_TWO_POINT_TRIMMING; |
528 | break; |
529 | case EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING: |
530 | default: |
531 | data->cal_type = TYPE_ONE_POINT_TRIMMING; |
532 | break; |
533 | } |
534 | |
535 | dev_info(&pdev->dev, "Calibration type is %d-point calibration\n" , |
536 | cal_type ? 2 : 1); |
537 | } |
538 | |
539 | static void exynos7_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp) |
540 | { |
541 | exynos_tmu_update_temp(data, EXYNOS7_THD_TEMP_FALL7_6 + 12, bit_off: 0, temp); |
542 | exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN, |
543 | EXYNOS_TMU_INTEN_FALL0_SHIFT + 0, enable: true); |
544 | } |
545 | |
546 | static void exynos7_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp) |
547 | { |
548 | exynos_tmu_update_temp(data, EXYNOS7_THD_TEMP_RISE7_6 + 12, bit_off: 16, temp); |
549 | exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN, |
550 | EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, enable: true); |
551 | } |
552 | |
553 | static void exynos7_tmu_disable_low(struct exynos_tmu_data *data) |
554 | { |
555 | exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN, |
556 | EXYNOS_TMU_INTEN_FALL0_SHIFT + 0, enable: false); |
557 | } |
558 | |
559 | static void exynos7_tmu_disable_high(struct exynos_tmu_data *data) |
560 | { |
561 | exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN, |
562 | EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, enable: false); |
563 | } |
564 | |
565 | static void exynos7_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp) |
566 | { |
567 | /* |
568 | * Like Exynos 4210, Exynos 7 does not seem to support critical temperature |
569 | * handling in hardware. Again, we still set a separate interrupt for it. |
570 | */ |
571 | exynos_tmu_update_temp(data, EXYNOS7_THD_TEMP_RISE7_6 + 0, bit_off: 16, temp); |
572 | exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN, |
573 | EXYNOS7_TMU_INTEN_RISE0_SHIFT + 7, enable: true); |
574 | } |
575 | |
576 | static void exynos7_tmu_initialize(struct platform_device *pdev) |
577 | { |
578 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
579 | unsigned int trim_info; |
580 | |
581 | trim_info = readl(addr: data->base + EXYNOS_TMU_REG_TRIMINFO); |
582 | sanitize_temp_error(data, trim_info); |
583 | } |
584 | |
585 | static void exynos4210_tmu_control(struct platform_device *pdev, bool on) |
586 | { |
587 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
588 | unsigned int con; |
589 | |
590 | con = get_con_reg(data, readl(addr: data->base + EXYNOS_TMU_REG_CONTROL)); |
591 | |
592 | if (on) |
593 | con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT); |
594 | else |
595 | con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT); |
596 | |
597 | writel(val: con, addr: data->base + EXYNOS_TMU_REG_CONTROL); |
598 | } |
599 | |
600 | static void exynos5433_tmu_control(struct platform_device *pdev, bool on) |
601 | { |
602 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
603 | unsigned int con, pd_det_en; |
604 | |
605 | con = get_con_reg(data, readl(addr: data->base + EXYNOS_TMU_REG_CONTROL)); |
606 | |
607 | if (on) |
608 | con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT); |
609 | else |
610 | con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT); |
611 | |
612 | pd_det_en = on ? EXYNOS5433_PD_DET_EN : 0; |
613 | |
614 | writel(val: pd_det_en, addr: data->base + EXYNOS5433_TMU_PD_DET_EN); |
615 | writel(val: con, addr: data->base + EXYNOS_TMU_REG_CONTROL); |
616 | } |
617 | |
618 | static void exynos7_tmu_control(struct platform_device *pdev, bool on) |
619 | { |
620 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
621 | unsigned int con; |
622 | |
623 | con = get_con_reg(data, readl(addr: data->base + EXYNOS_TMU_REG_CONTROL)); |
624 | |
625 | if (on) { |
626 | con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT); |
627 | con |= BIT(EXYNOS7_PD_DET_EN_SHIFT); |
628 | } else { |
629 | con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT); |
630 | con &= ~BIT(EXYNOS7_PD_DET_EN_SHIFT); |
631 | } |
632 | |
633 | writel(val: con, addr: data->base + EXYNOS_TMU_REG_CONTROL); |
634 | } |
635 | |
636 | static int exynos_get_temp(struct thermal_zone_device *tz, int *temp) |
637 | { |
638 | struct exynos_tmu_data *data = thermal_zone_device_priv(tzd: tz); |
639 | int value, ret = 0; |
640 | |
641 | if (!data || !data->tmu_read) |
642 | return -EINVAL; |
643 | else if (!data->enabled) |
644 | /* |
645 | * Called too early, probably |
646 | * from thermal_zone_of_sensor_register(). |
647 | */ |
648 | return -EAGAIN; |
649 | |
650 | mutex_lock(&data->lock); |
651 | clk_enable(clk: data->clk); |
652 | |
653 | value = data->tmu_read(data); |
654 | if (value < 0) |
655 | ret = value; |
656 | else |
657 | *temp = code_to_temp(data, temp_code: value) * MCELSIUS; |
658 | |
659 | clk_disable(clk: data->clk); |
660 | mutex_unlock(lock: &data->lock); |
661 | |
662 | return ret; |
663 | } |
664 | |
665 | #ifdef CONFIG_THERMAL_EMULATION |
666 | static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val, |
667 | int temp) |
668 | { |
669 | if (temp) { |
670 | temp /= MCELSIUS; |
671 | |
672 | val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT); |
673 | val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT); |
674 | if (data->soc == SOC_ARCH_EXYNOS7) { |
675 | val &= ~(EXYNOS7_EMUL_DATA_MASK << |
676 | EXYNOS7_EMUL_DATA_SHIFT); |
677 | val |= (temp_to_code(data, temp) << |
678 | EXYNOS7_EMUL_DATA_SHIFT) | |
679 | EXYNOS_EMUL_ENABLE; |
680 | } else { |
681 | val &= ~(EXYNOS_EMUL_DATA_MASK << |
682 | EXYNOS_EMUL_DATA_SHIFT); |
683 | val |= (temp_to_code(data, temp) << |
684 | EXYNOS_EMUL_DATA_SHIFT) | |
685 | EXYNOS_EMUL_ENABLE; |
686 | } |
687 | } else { |
688 | val &= ~EXYNOS_EMUL_ENABLE; |
689 | } |
690 | |
691 | return val; |
692 | } |
693 | |
694 | static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data, |
695 | int temp) |
696 | { |
697 | unsigned int val; |
698 | u32 emul_con; |
699 | |
700 | if (data->soc == SOC_ARCH_EXYNOS5260) |
701 | emul_con = EXYNOS5260_EMUL_CON; |
702 | else if (data->soc == SOC_ARCH_EXYNOS5433) |
703 | emul_con = EXYNOS5433_TMU_EMUL_CON; |
704 | else if (data->soc == SOC_ARCH_EXYNOS7) |
705 | emul_con = EXYNOS7_TMU_REG_EMUL_CON; |
706 | else |
707 | emul_con = EXYNOS_EMUL_CON; |
708 | |
709 | val = readl(addr: data->base + emul_con); |
710 | val = get_emul_con_reg(data, val, temp); |
711 | writel(val, addr: data->base + emul_con); |
712 | } |
713 | |
714 | static int exynos_tmu_set_emulation(struct thermal_zone_device *tz, int temp) |
715 | { |
716 | struct exynos_tmu_data *data = thermal_zone_device_priv(tzd: tz); |
717 | int ret = -EINVAL; |
718 | |
719 | if (data->soc == SOC_ARCH_EXYNOS4210) |
720 | goto out; |
721 | |
722 | if (temp && temp < MCELSIUS) |
723 | goto out; |
724 | |
725 | mutex_lock(&data->lock); |
726 | clk_enable(clk: data->clk); |
727 | data->tmu_set_emulation(data, temp); |
728 | clk_disable(clk: data->clk); |
729 | mutex_unlock(lock: &data->lock); |
730 | return 0; |
731 | out: |
732 | return ret; |
733 | } |
734 | #else |
735 | #define exynos4412_tmu_set_emulation NULL |
736 | static int exynos_tmu_set_emulation(struct thermal_zone_device *tz, int temp) |
737 | { return -EINVAL; } |
738 | #endif /* CONFIG_THERMAL_EMULATION */ |
739 | |
740 | static int exynos4210_tmu_read(struct exynos_tmu_data *data) |
741 | { |
742 | int ret = readb(addr: data->base + EXYNOS_TMU_REG_CURRENT_TEMP); |
743 | |
744 | /* "temp_code" should range between 75 and 175 */ |
745 | return (ret < 75 || ret > 175) ? -ENODATA : ret; |
746 | } |
747 | |
748 | static int exynos4412_tmu_read(struct exynos_tmu_data *data) |
749 | { |
750 | return readb(addr: data->base + EXYNOS_TMU_REG_CURRENT_TEMP); |
751 | } |
752 | |
753 | static int exynos7_tmu_read(struct exynos_tmu_data *data) |
754 | { |
755 | return readw(addr: data->base + EXYNOS_TMU_REG_CURRENT_TEMP) & |
756 | EXYNOS7_TMU_TEMP_MASK; |
757 | } |
758 | |
759 | static irqreturn_t exynos_tmu_threaded_irq(int irq, void *id) |
760 | { |
761 | struct exynos_tmu_data *data = id; |
762 | |
763 | thermal_zone_device_update(data->tzd, THERMAL_EVENT_UNSPECIFIED); |
764 | |
765 | mutex_lock(&data->lock); |
766 | clk_enable(clk: data->clk); |
767 | |
768 | /* TODO: take action based on particular interrupt */ |
769 | data->tmu_clear_irqs(data); |
770 | |
771 | clk_disable(clk: data->clk); |
772 | mutex_unlock(lock: &data->lock); |
773 | |
774 | return IRQ_HANDLED; |
775 | } |
776 | |
777 | static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data) |
778 | { |
779 | unsigned int val_irq; |
780 | u32 tmu_intstat, tmu_intclear; |
781 | |
782 | if (data->soc == SOC_ARCH_EXYNOS5260) { |
783 | tmu_intstat = EXYNOS5260_TMU_REG_INTSTAT; |
784 | tmu_intclear = EXYNOS5260_TMU_REG_INTCLEAR; |
785 | } else if (data->soc == SOC_ARCH_EXYNOS7) { |
786 | tmu_intstat = EXYNOS7_TMU_REG_INTPEND; |
787 | tmu_intclear = EXYNOS7_TMU_REG_INTPEND; |
788 | } else if (data->soc == SOC_ARCH_EXYNOS5433) { |
789 | tmu_intstat = EXYNOS5433_TMU_REG_INTPEND; |
790 | tmu_intclear = EXYNOS5433_TMU_REG_INTPEND; |
791 | } else { |
792 | tmu_intstat = EXYNOS_TMU_REG_INTSTAT; |
793 | tmu_intclear = EXYNOS_TMU_REG_INTCLEAR; |
794 | } |
795 | |
796 | val_irq = readl(addr: data->base + tmu_intstat); |
797 | /* |
798 | * Clear the interrupts. Please note that the documentation for |
799 | * Exynos3250, Exynos4412, Exynos5250 and Exynos5260 incorrectly |
800 | * states that INTCLEAR register has a different placing of bits |
801 | * responsible for FALL IRQs than INTSTAT register. Exynos5420 |
802 | * and Exynos5440 documentation is correct (Exynos4210 doesn't |
803 | * support FALL IRQs at all). |
804 | */ |
805 | writel(val: val_irq, addr: data->base + tmu_intclear); |
806 | } |
807 | |
808 | static const struct of_device_id exynos_tmu_match[] = { |
809 | { |
810 | .compatible = "samsung,exynos3250-tmu" , |
811 | .data = (const void *)SOC_ARCH_EXYNOS3250, |
812 | }, { |
813 | .compatible = "samsung,exynos4210-tmu" , |
814 | .data = (const void *)SOC_ARCH_EXYNOS4210, |
815 | }, { |
816 | .compatible = "samsung,exynos4412-tmu" , |
817 | .data = (const void *)SOC_ARCH_EXYNOS4412, |
818 | }, { |
819 | .compatible = "samsung,exynos5250-tmu" , |
820 | .data = (const void *)SOC_ARCH_EXYNOS5250, |
821 | }, { |
822 | .compatible = "samsung,exynos5260-tmu" , |
823 | .data = (const void *)SOC_ARCH_EXYNOS5260, |
824 | }, { |
825 | .compatible = "samsung,exynos5420-tmu" , |
826 | .data = (const void *)SOC_ARCH_EXYNOS5420, |
827 | }, { |
828 | .compatible = "samsung,exynos5420-tmu-ext-triminfo" , |
829 | .data = (const void *)SOC_ARCH_EXYNOS5420_TRIMINFO, |
830 | }, { |
831 | .compatible = "samsung,exynos5433-tmu" , |
832 | .data = (const void *)SOC_ARCH_EXYNOS5433, |
833 | }, { |
834 | .compatible = "samsung,exynos7-tmu" , |
835 | .data = (const void *)SOC_ARCH_EXYNOS7, |
836 | }, |
837 | { }, |
838 | }; |
839 | MODULE_DEVICE_TABLE(of, exynos_tmu_match); |
840 | |
841 | static int exynos_map_dt_data(struct platform_device *pdev) |
842 | { |
843 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
844 | struct resource res; |
845 | |
846 | if (!data || !pdev->dev.of_node) |
847 | return -ENODEV; |
848 | |
849 | data->irq = irq_of_parse_and_map(node: pdev->dev.of_node, index: 0); |
850 | if (data->irq <= 0) { |
851 | dev_err(&pdev->dev, "failed to get IRQ\n" ); |
852 | return -ENODEV; |
853 | } |
854 | |
855 | if (of_address_to_resource(dev: pdev->dev.of_node, index: 0, r: &res)) { |
856 | dev_err(&pdev->dev, "failed to get Resource 0\n" ); |
857 | return -ENODEV; |
858 | } |
859 | |
860 | data->base = devm_ioremap(dev: &pdev->dev, offset: res.start, size: resource_size(res: &res)); |
861 | if (!data->base) { |
862 | dev_err(&pdev->dev, "Failed to ioremap memory\n" ); |
863 | return -EADDRNOTAVAIL; |
864 | } |
865 | |
866 | data->soc = (uintptr_t)of_device_get_match_data(dev: &pdev->dev); |
867 | |
868 | switch (data->soc) { |
869 | case SOC_ARCH_EXYNOS4210: |
870 | data->tmu_set_low_temp = exynos4210_tmu_set_low_temp; |
871 | data->tmu_set_high_temp = exynos4210_tmu_set_high_temp; |
872 | data->tmu_disable_low = exynos4210_tmu_disable_low; |
873 | data->tmu_disable_high = exynos4210_tmu_disable_high; |
874 | data->tmu_set_crit_temp = exynos4210_tmu_set_crit_temp; |
875 | data->tmu_initialize = exynos4210_tmu_initialize; |
876 | data->tmu_control = exynos4210_tmu_control; |
877 | data->tmu_read = exynos4210_tmu_read; |
878 | data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; |
879 | data->gain = 15; |
880 | data->reference_voltage = 7; |
881 | data->efuse_value = 55; |
882 | data->min_efuse_value = 40; |
883 | data->max_efuse_value = 100; |
884 | break; |
885 | case SOC_ARCH_EXYNOS3250: |
886 | case SOC_ARCH_EXYNOS4412: |
887 | case SOC_ARCH_EXYNOS5250: |
888 | case SOC_ARCH_EXYNOS5260: |
889 | case SOC_ARCH_EXYNOS5420: |
890 | case SOC_ARCH_EXYNOS5420_TRIMINFO: |
891 | data->tmu_set_low_temp = exynos4412_tmu_set_low_temp; |
892 | data->tmu_set_high_temp = exynos4412_tmu_set_high_temp; |
893 | data->tmu_disable_low = exynos4412_tmu_disable_low; |
894 | data->tmu_disable_high = exynos4210_tmu_disable_high; |
895 | data->tmu_set_crit_temp = exynos4412_tmu_set_crit_temp; |
896 | data->tmu_initialize = exynos4412_tmu_initialize; |
897 | data->tmu_control = exynos4210_tmu_control; |
898 | data->tmu_read = exynos4412_tmu_read; |
899 | data->tmu_set_emulation = exynos4412_tmu_set_emulation; |
900 | data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; |
901 | data->gain = 8; |
902 | data->reference_voltage = 16; |
903 | data->efuse_value = 55; |
904 | if (data->soc != SOC_ARCH_EXYNOS5420 && |
905 | data->soc != SOC_ARCH_EXYNOS5420_TRIMINFO) |
906 | data->min_efuse_value = 40; |
907 | else |
908 | data->min_efuse_value = 0; |
909 | data->max_efuse_value = 100; |
910 | break; |
911 | case SOC_ARCH_EXYNOS5433: |
912 | data->tmu_set_low_temp = exynos5433_tmu_set_low_temp; |
913 | data->tmu_set_high_temp = exynos5433_tmu_set_high_temp; |
914 | data->tmu_disable_low = exynos5433_tmu_disable_low; |
915 | data->tmu_disable_high = exynos5433_tmu_disable_high; |
916 | data->tmu_set_crit_temp = exynos5433_tmu_set_crit_temp; |
917 | data->tmu_initialize = exynos5433_tmu_initialize; |
918 | data->tmu_control = exynos5433_tmu_control; |
919 | data->tmu_read = exynos4412_tmu_read; |
920 | data->tmu_set_emulation = exynos4412_tmu_set_emulation; |
921 | data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; |
922 | data->gain = 8; |
923 | if (res.start == EXYNOS5433_G3D_BASE) |
924 | data->reference_voltage = 23; |
925 | else |
926 | data->reference_voltage = 16; |
927 | data->efuse_value = 75; |
928 | data->min_efuse_value = 40; |
929 | data->max_efuse_value = 150; |
930 | break; |
931 | case SOC_ARCH_EXYNOS7: |
932 | data->tmu_set_low_temp = exynos7_tmu_set_low_temp; |
933 | data->tmu_set_high_temp = exynos7_tmu_set_high_temp; |
934 | data->tmu_disable_low = exynos7_tmu_disable_low; |
935 | data->tmu_disable_high = exynos7_tmu_disable_high; |
936 | data->tmu_set_crit_temp = exynos7_tmu_set_crit_temp; |
937 | data->tmu_initialize = exynos7_tmu_initialize; |
938 | data->tmu_control = exynos7_tmu_control; |
939 | data->tmu_read = exynos7_tmu_read; |
940 | data->tmu_set_emulation = exynos4412_tmu_set_emulation; |
941 | data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; |
942 | data->gain = 9; |
943 | data->reference_voltage = 17; |
944 | data->efuse_value = 75; |
945 | data->min_efuse_value = 15; |
946 | data->max_efuse_value = 100; |
947 | break; |
948 | default: |
949 | dev_err(&pdev->dev, "Platform not supported\n" ); |
950 | return -EINVAL; |
951 | } |
952 | |
953 | data->cal_type = TYPE_ONE_POINT_TRIMMING; |
954 | |
955 | /* |
956 | * Check if the TMU shares some registers and then try to map the |
957 | * memory of common registers. |
958 | */ |
959 | if (data->soc != SOC_ARCH_EXYNOS5420_TRIMINFO) |
960 | return 0; |
961 | |
962 | if (of_address_to_resource(dev: pdev->dev.of_node, index: 1, r: &res)) { |
963 | dev_err(&pdev->dev, "failed to get Resource 1\n" ); |
964 | return -ENODEV; |
965 | } |
966 | |
967 | data->base_second = devm_ioremap(dev: &pdev->dev, offset: res.start, |
968 | size: resource_size(res: &res)); |
969 | if (!data->base_second) { |
970 | dev_err(&pdev->dev, "Failed to ioremap memory\n" ); |
971 | return -ENOMEM; |
972 | } |
973 | |
974 | return 0; |
975 | } |
976 | |
977 | static int exynos_set_trips(struct thermal_zone_device *tz, int low, int high) |
978 | { |
979 | struct exynos_tmu_data *data = thermal_zone_device_priv(tzd: tz); |
980 | |
981 | mutex_lock(&data->lock); |
982 | clk_enable(clk: data->clk); |
983 | |
984 | if (low > INT_MIN) |
985 | data->tmu_set_low_temp(data, low / MCELSIUS); |
986 | else |
987 | data->tmu_disable_low(data); |
988 | if (high < INT_MAX) |
989 | data->tmu_set_high_temp(data, high / MCELSIUS); |
990 | else |
991 | data->tmu_disable_high(data); |
992 | |
993 | clk_disable(clk: data->clk); |
994 | mutex_unlock(lock: &data->lock); |
995 | |
996 | return 0; |
997 | } |
998 | |
999 | static const struct thermal_zone_device_ops exynos_sensor_ops = { |
1000 | .get_temp = exynos_get_temp, |
1001 | .set_emul_temp = exynos_tmu_set_emulation, |
1002 | .set_trips = exynos_set_trips, |
1003 | }; |
1004 | |
1005 | static int exynos_tmu_probe(struct platform_device *pdev) |
1006 | { |
1007 | struct exynos_tmu_data *data; |
1008 | int ret; |
1009 | |
1010 | data = devm_kzalloc(dev: &pdev->dev, size: sizeof(struct exynos_tmu_data), |
1011 | GFP_KERNEL); |
1012 | if (!data) |
1013 | return -ENOMEM; |
1014 | |
1015 | platform_set_drvdata(pdev, data); |
1016 | mutex_init(&data->lock); |
1017 | |
1018 | /* |
1019 | * Try enabling the regulator if found |
1020 | * TODO: Add regulator as an SOC feature, so that regulator enable |
1021 | * is a compulsory call. |
1022 | */ |
1023 | ret = devm_regulator_get_enable_optional(dev: &pdev->dev, id: "vtmu" ); |
1024 | switch (ret) { |
1025 | case 0: |
1026 | case -ENODEV: |
1027 | break; |
1028 | case -EPROBE_DEFER: |
1029 | return -EPROBE_DEFER; |
1030 | default: |
1031 | dev_err(&pdev->dev, "Failed to get enabled regulator: %d\n" , |
1032 | ret); |
1033 | return ret; |
1034 | } |
1035 | |
1036 | ret = exynos_map_dt_data(pdev); |
1037 | if (ret) |
1038 | return ret; |
1039 | |
1040 | data->clk = devm_clk_get(dev: &pdev->dev, id: "tmu_apbif" ); |
1041 | if (IS_ERR(ptr: data->clk)) { |
1042 | dev_err(&pdev->dev, "Failed to get clock\n" ); |
1043 | return PTR_ERR(ptr: data->clk); |
1044 | } |
1045 | |
1046 | data->clk_sec = devm_clk_get(dev: &pdev->dev, id: "tmu_triminfo_apbif" ); |
1047 | if (IS_ERR(ptr: data->clk_sec)) { |
1048 | if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) { |
1049 | dev_err(&pdev->dev, "Failed to get triminfo clock\n" ); |
1050 | return PTR_ERR(ptr: data->clk_sec); |
1051 | } |
1052 | } else { |
1053 | ret = clk_prepare(clk: data->clk_sec); |
1054 | if (ret) { |
1055 | dev_err(&pdev->dev, "Failed to get clock\n" ); |
1056 | return ret; |
1057 | } |
1058 | } |
1059 | |
1060 | ret = clk_prepare(clk: data->clk); |
1061 | if (ret) { |
1062 | dev_err(&pdev->dev, "Failed to get clock\n" ); |
1063 | goto err_clk_sec; |
1064 | } |
1065 | |
1066 | switch (data->soc) { |
1067 | case SOC_ARCH_EXYNOS5433: |
1068 | case SOC_ARCH_EXYNOS7: |
1069 | data->sclk = devm_clk_get(dev: &pdev->dev, id: "tmu_sclk" ); |
1070 | if (IS_ERR(ptr: data->sclk)) { |
1071 | dev_err(&pdev->dev, "Failed to get sclk\n" ); |
1072 | ret = PTR_ERR(ptr: data->sclk); |
1073 | goto err_clk; |
1074 | } else { |
1075 | ret = clk_prepare_enable(clk: data->sclk); |
1076 | if (ret) { |
1077 | dev_err(&pdev->dev, "Failed to enable sclk\n" ); |
1078 | goto err_clk; |
1079 | } |
1080 | } |
1081 | break; |
1082 | default: |
1083 | break; |
1084 | } |
1085 | |
1086 | ret = exynos_tmu_initialize(pdev); |
1087 | if (ret) { |
1088 | dev_err(&pdev->dev, "Failed to initialize TMU\n" ); |
1089 | goto err_sclk; |
1090 | } |
1091 | |
1092 | data->tzd = devm_thermal_of_zone_register(dev: &pdev->dev, id: 0, data, |
1093 | ops: &exynos_sensor_ops); |
1094 | if (IS_ERR(ptr: data->tzd)) { |
1095 | ret = PTR_ERR(ptr: data->tzd); |
1096 | if (ret != -EPROBE_DEFER) |
1097 | dev_err(&pdev->dev, "Failed to register sensor: %d\n" , |
1098 | ret); |
1099 | goto err_sclk; |
1100 | } |
1101 | |
1102 | ret = exynos_thermal_zone_configure(pdev); |
1103 | if (ret) { |
1104 | dev_err(&pdev->dev, "Failed to configure the thermal zone\n" ); |
1105 | goto err_sclk; |
1106 | } |
1107 | |
1108 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq: data->irq, NULL, |
1109 | thread_fn: exynos_tmu_threaded_irq, |
1110 | IRQF_TRIGGER_RISING |
1111 | | IRQF_SHARED | IRQF_ONESHOT, |
1112 | devname: dev_name(dev: &pdev->dev), dev_id: data); |
1113 | if (ret) { |
1114 | dev_err(&pdev->dev, "Failed to request irq: %d\n" , data->irq); |
1115 | goto err_sclk; |
1116 | } |
1117 | |
1118 | exynos_tmu_control(pdev, on: true); |
1119 | return 0; |
1120 | |
1121 | err_sclk: |
1122 | clk_disable_unprepare(clk: data->sclk); |
1123 | err_clk: |
1124 | clk_unprepare(clk: data->clk); |
1125 | err_clk_sec: |
1126 | if (!IS_ERR(ptr: data->clk_sec)) |
1127 | clk_unprepare(clk: data->clk_sec); |
1128 | return ret; |
1129 | } |
1130 | |
1131 | static void exynos_tmu_remove(struct platform_device *pdev) |
1132 | { |
1133 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
1134 | |
1135 | exynos_tmu_control(pdev, on: false); |
1136 | |
1137 | clk_disable_unprepare(clk: data->sclk); |
1138 | clk_unprepare(clk: data->clk); |
1139 | if (!IS_ERR(ptr: data->clk_sec)) |
1140 | clk_unprepare(clk: data->clk_sec); |
1141 | } |
1142 | |
1143 | #ifdef CONFIG_PM_SLEEP |
1144 | static int exynos_tmu_suspend(struct device *dev) |
1145 | { |
1146 | exynos_tmu_control(to_platform_device(dev), on: false); |
1147 | |
1148 | return 0; |
1149 | } |
1150 | |
1151 | static int exynos_tmu_resume(struct device *dev) |
1152 | { |
1153 | struct platform_device *pdev = to_platform_device(dev); |
1154 | |
1155 | exynos_tmu_initialize(pdev); |
1156 | exynos_tmu_control(pdev, on: true); |
1157 | |
1158 | return 0; |
1159 | } |
1160 | |
1161 | static SIMPLE_DEV_PM_OPS(exynos_tmu_pm, |
1162 | exynos_tmu_suspend, exynos_tmu_resume); |
1163 | #define EXYNOS_TMU_PM (&exynos_tmu_pm) |
1164 | #else |
1165 | #define EXYNOS_TMU_PM NULL |
1166 | #endif |
1167 | |
1168 | static struct platform_driver exynos_tmu_driver = { |
1169 | .driver = { |
1170 | .name = "exynos-tmu" , |
1171 | .pm = EXYNOS_TMU_PM, |
1172 | .of_match_table = exynos_tmu_match, |
1173 | }, |
1174 | .probe = exynos_tmu_probe, |
1175 | .remove_new = exynos_tmu_remove, |
1176 | }; |
1177 | |
1178 | module_platform_driver(exynos_tmu_driver); |
1179 | |
1180 | MODULE_DESCRIPTION("Exynos TMU Driver" ); |
1181 | MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>" ); |
1182 | MODULE_LICENSE("GPL" ); |
1183 | MODULE_ALIAS("platform:exynos-tmu" ); |
1184 | |