xref: /linux/drivers/thermal/samsung/exynos_tmu.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
259dfa54cSAmit Daniel Kachhap /*
3ca07ee4eSKrzysztof Kozlowski  * exynos_tmu.c - Samsung Exynos TMU (Thermal Management Unit)
459dfa54cSAmit Daniel Kachhap  *
53b6a1a80SLukasz Majewski  *  Copyright (C) 2014 Samsung Electronics
63b6a1a80SLukasz Majewski  *  Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
73b6a1a80SLukasz Majewski  *  Lukasz Majewski <l.majewski@samsung.com>
83b6a1a80SLukasz Majewski  *
959dfa54cSAmit Daniel Kachhap  *  Copyright (C) 2011 Samsung Electronics
1059dfa54cSAmit Daniel Kachhap  *  Donggeun Kim <dg77.kim@samsung.com>
1159dfa54cSAmit Daniel Kachhap  *  Amit Daniel Kachhap <amit.kachhap@linaro.org>
1259dfa54cSAmit Daniel Kachhap  */
1359dfa54cSAmit Daniel Kachhap 
1459dfa54cSAmit Daniel Kachhap #include <linux/clk.h>
1559dfa54cSAmit Daniel Kachhap #include <linux/io.h>
1659dfa54cSAmit Daniel Kachhap #include <linux/interrupt.h>
1759dfa54cSAmit Daniel Kachhap #include <linux/module.h>
18f6a756e8SRob Herring #include <linux/of.h>
19cebe7373SAmit Daniel Kachhap #include <linux/of_address.h>
20cebe7373SAmit Daniel Kachhap #include <linux/of_irq.h>
2159dfa54cSAmit Daniel Kachhap #include <linux/platform_device.h>
22498d22f6SAmit Daniel Kachhap #include <linux/regulator/consumer.h>
239272d2d4SDaniel Lezcano #include <linux/thermal.h>
2459dfa54cSAmit Daniel Kachhap 
257efd18a2SBartlomiej Zolnierkiewicz #include <dt-bindings/thermal/thermal_exynos.h>
267efd18a2SBartlomiej Zolnierkiewicz 
272845f6ecSBartlomiej Zolnierkiewicz /* Exynos generic registers */
282845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_REG_TRIMINFO		0x0
292845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_REG_CONTROL		0x20
302845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_REG_STATUS		0x28
312845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_REG_CURRENT_TEMP	0x40
322845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_REG_INTEN		0x70
332845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_REG_INTSTAT		0x74
342845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_REG_INTCLEAR		0x78
352845f6ecSBartlomiej Zolnierkiewicz 
362845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_TEMP_MASK		0xff
372845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_REF_VOLTAGE_SHIFT	24
382845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_REF_VOLTAGE_MASK	0x1f
392845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_BUF_SLOPE_SEL_MASK	0xf
402845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT	8
412845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_CORE_EN_SHIFT	0
422845f6ecSBartlomiej Zolnierkiewicz 
432845f6ecSBartlomiej Zolnierkiewicz /* Exynos3250 specific registers */
442845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_TRIMINFO_CON1	0x10
452845f6ecSBartlomiej Zolnierkiewicz 
462845f6ecSBartlomiej Zolnierkiewicz /* Exynos4210 specific registers */
472845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS4210_TMU_REG_THRESHOLD_TEMP	0x44
482845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS4210_TMU_REG_TRIG_LEVEL0	0x50
492845f6ecSBartlomiej Zolnierkiewicz 
502845f6ecSBartlomiej Zolnierkiewicz /* Exynos5250, Exynos4412, Exynos3250 specific registers */
512845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_TRIMINFO_CON2	0x14
522845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_THD_TEMP_RISE		0x50
532845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_THD_TEMP_FALL		0x54
542845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_EMUL_CON		0x80
552845f6ecSBartlomiej Zolnierkiewicz 
562845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TRIMINFO_RELOAD_ENABLE	1
572845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TRIMINFO_25_SHIFT	0
582845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TRIMINFO_85_SHIFT	8
592845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_TRIP_MODE_SHIFT	13
602845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_TRIP_MODE_MASK	0x7
612845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_THERM_TRIP_EN_SHIFT	12
622845f6ecSBartlomiej Zolnierkiewicz 
632845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_INTEN_RISE0_SHIFT	0
642845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_TMU_INTEN_FALL0_SHIFT	16
652845f6ecSBartlomiej Zolnierkiewicz 
662845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_EMUL_TIME	0x57F0
672845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_EMUL_TIME_MASK	0xffff
682845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_EMUL_TIME_SHIFT	16
692845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_EMUL_DATA_SHIFT	8
702845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_EMUL_DATA_MASK	0xFF
712845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS_EMUL_ENABLE	0x1
722845f6ecSBartlomiej Zolnierkiewicz 
732845f6ecSBartlomiej Zolnierkiewicz /* Exynos5260 specific */
742845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS5260_TMU_REG_INTEN		0xC0
752845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS5260_TMU_REG_INTSTAT		0xC4
762845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS5260_TMU_REG_INTCLEAR		0xC8
772845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS5260_EMUL_CON			0x100
782845f6ecSBartlomiej Zolnierkiewicz 
792845f6ecSBartlomiej Zolnierkiewicz /* Exynos4412 specific */
802845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS4412_MUX_ADDR_VALUE          6
812845f6ecSBartlomiej Zolnierkiewicz #define EXYNOS4412_MUX_ADDR_SHIFT          20
822845f6ecSBartlomiej Zolnierkiewicz 
83488c7455SChanwoo Choi /* Exynos5433 specific registers */
84488c7455SChanwoo Choi #define EXYNOS5433_THD_TEMP_RISE3_0		0x050
85488c7455SChanwoo Choi #define EXYNOS5433_THD_TEMP_RISE7_4		0x054
86488c7455SChanwoo Choi #define EXYNOS5433_THD_TEMP_FALL3_0		0x060
87488c7455SChanwoo Choi #define EXYNOS5433_THD_TEMP_FALL7_4		0x064
88488c7455SChanwoo Choi #define EXYNOS5433_TMU_REG_INTEN		0x0c0
89488c7455SChanwoo Choi #define EXYNOS5433_TMU_REG_INTPEND		0x0c8
90488c7455SChanwoo Choi #define EXYNOS5433_TMU_EMUL_CON			0x110
91488c7455SChanwoo Choi #define EXYNOS5433_TMU_PD_DET_EN		0x130
92488c7455SChanwoo Choi 
93488c7455SChanwoo Choi #define EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT	16
94488c7455SChanwoo Choi #define EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT	23
95488c7455SChanwoo Choi #define EXYNOS5433_TRIMINFO_SENSOR_ID_MASK	\
96488c7455SChanwoo Choi 			(0xf << EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT)
97488c7455SChanwoo Choi #define EXYNOS5433_TRIMINFO_CALIB_SEL_MASK	BIT(23)
98488c7455SChanwoo Choi 
99488c7455SChanwoo Choi #define EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING	0
100488c7455SChanwoo Choi #define EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING	1
101488c7455SChanwoo Choi 
102488c7455SChanwoo Choi #define EXYNOS5433_PD_DET_EN			1
103488c7455SChanwoo Choi 
10461020d18SBartlomiej Zolnierkiewicz #define EXYNOS5433_G3D_BASE			0x10070000
10559dfa54cSAmit Daniel Kachhap 
1066c247393SAbhilash Kesavan /* Exynos7 specific registers */
1076c247393SAbhilash Kesavan #define EXYNOS7_THD_TEMP_RISE7_6		0x50
1086c247393SAbhilash Kesavan #define EXYNOS7_THD_TEMP_FALL7_6		0x60
1096c247393SAbhilash Kesavan #define EXYNOS7_TMU_REG_INTEN			0x110
1106c247393SAbhilash Kesavan #define EXYNOS7_TMU_REG_INTPEND			0x118
1116c247393SAbhilash Kesavan #define EXYNOS7_TMU_REG_EMUL_CON		0x160
1126c247393SAbhilash Kesavan 
1136c247393SAbhilash Kesavan #define EXYNOS7_TMU_TEMP_MASK			0x1ff
1146c247393SAbhilash Kesavan #define EXYNOS7_PD_DET_EN_SHIFT			23
1156c247393SAbhilash Kesavan #define EXYNOS7_TMU_INTEN_RISE0_SHIFT		0
1166c247393SAbhilash Kesavan #define EXYNOS7_EMUL_DATA_SHIFT			7
1176c247393SAbhilash Kesavan #define EXYNOS7_EMUL_DATA_MASK			0x1ff
1186c247393SAbhilash Kesavan 
119718b4ca1SBartlomiej Zolnierkiewicz #define EXYNOS_FIRST_POINT_TRIM			25
120718b4ca1SBartlomiej Zolnierkiewicz #define EXYNOS_SECOND_POINT_TRIM		85
121718b4ca1SBartlomiej Zolnierkiewicz 
12209d29426SBartlomiej Zolnierkiewicz #define EXYNOS_NOISE_CANCEL_MODE		4
12309d29426SBartlomiej Zolnierkiewicz 
1243b6a1a80SLukasz Majewski #define MCELSIUS	1000
1257efd18a2SBartlomiej Zolnierkiewicz 
1267efd18a2SBartlomiej Zolnierkiewicz enum soc_type {
1277efd18a2SBartlomiej Zolnierkiewicz 	SOC_ARCH_EXYNOS3250 = 1,
1287efd18a2SBartlomiej Zolnierkiewicz 	SOC_ARCH_EXYNOS4210,
1297efd18a2SBartlomiej Zolnierkiewicz 	SOC_ARCH_EXYNOS4412,
1307efd18a2SBartlomiej Zolnierkiewicz 	SOC_ARCH_EXYNOS5250,
1317efd18a2SBartlomiej Zolnierkiewicz 	SOC_ARCH_EXYNOS5260,
1327efd18a2SBartlomiej Zolnierkiewicz 	SOC_ARCH_EXYNOS5420,
1337efd18a2SBartlomiej Zolnierkiewicz 	SOC_ARCH_EXYNOS5420_TRIMINFO,
1347efd18a2SBartlomiej Zolnierkiewicz 	SOC_ARCH_EXYNOS5433,
1357efd18a2SBartlomiej Zolnierkiewicz 	SOC_ARCH_EXYNOS7,
1367efd18a2SBartlomiej Zolnierkiewicz };
1377efd18a2SBartlomiej Zolnierkiewicz 
138cebe7373SAmit Daniel Kachhap /**
139cebe7373SAmit Daniel Kachhap  * struct exynos_tmu_data : A structure to hold the private data of the TMU
1409625e9e6SAmit Kucheria  *			    driver
141cebe7373SAmit Daniel Kachhap  * @base: base address of the single instance of the TMU controller.
1429025d563SNaveen Krishna Chatradhi  * @base_second: base address of the common registers of the TMU controller.
143cebe7373SAmit Daniel Kachhap  * @irq: irq number of the TMU controller.
144cebe7373SAmit Daniel Kachhap  * @soc: id of the SOC type.
145cebe7373SAmit Daniel Kachhap  * @lock: lock to implement synchronization.
146cebe7373SAmit Daniel Kachhap  * @clk: pointer to the clock structure.
14714a11dc7SNaveen Krishna Chatradhi  * @clk_sec: pointer to the clock structure for accessing the base_second.
1486c247393SAbhilash Kesavan  * @sclk: pointer to the clock structure for accessing the tmu special clk.
149199b3e3cSBartlomiej Zolnierkiewicz  * @cal_type: calibration type for temperature
150e3ed3649SBartlomiej Zolnierkiewicz  * @efuse_value: SoC defined fuse value
151e3ed3649SBartlomiej Zolnierkiewicz  * @min_efuse_value: minimum valid trimming data
152e3ed3649SBartlomiej Zolnierkiewicz  * @max_efuse_value: maximum valid trimming data
153cebe7373SAmit Daniel Kachhap  * @temp_error1: fused value of the first point trim.
154cebe7373SAmit Daniel Kachhap  * @temp_error2: fused value of the second point trim.
155fccfe099SBartlomiej Zolnierkiewicz  * @gain: gain of amplifier in the positive-TC generator block
156fccfe099SBartlomiej Zolnierkiewicz  *	0 < gain <= 15
15761020d18SBartlomiej Zolnierkiewicz  * @reference_voltage: reference voltage of amplifier
15861020d18SBartlomiej Zolnierkiewicz  *	in the positive-TC generator block
15961020d18SBartlomiej Zolnierkiewicz  *	0 < reference_voltage <= 31
1609625e9e6SAmit Kucheria  * @tzd: pointer to thermal_zone_device structure
16188fc6f73SMarek Szyprowski  * @enabled: current status of TMU device
1625314b154SMateusz Majewski  * @tmu_set_low_temp: SoC specific method to set trip (falling threshold)
1635314b154SMateusz Majewski  * @tmu_set_high_temp: SoC specific method to set trip (rising threshold)
1645314b154SMateusz Majewski  * @tmu_set_crit_temp: SoC specific method to set critical temperature
1655314b154SMateusz Majewski  * @tmu_disable_low: SoC specific method to disable an interrupt (falling threshold)
1665314b154SMateusz Majewski  * @tmu_disable_high: SoC specific method to disable an interrupt (rising threshold)
16772d1100bSBartlomiej Zolnierkiewicz  * @tmu_initialize: SoC specific TMU initialization method
16837f9034fSBartlomiej Zolnierkiewicz  * @tmu_control: SoC specific TMU control method
169b79985caSBartlomiej Zolnierkiewicz  * @tmu_read: SoC specific TMU temperature read method
170285d994aSBartlomiej Zolnierkiewicz  * @tmu_set_emulation: SoC specific TMU emulation setting method
171a7331f72SBartlomiej Zolnierkiewicz  * @tmu_clear_irqs: SoC specific TMU interrupts clearing method
172cebe7373SAmit Daniel Kachhap  */
17359dfa54cSAmit Daniel Kachhap struct exynos_tmu_data {
17459dfa54cSAmit Daniel Kachhap 	void __iomem *base;
1759025d563SNaveen Krishna Chatradhi 	void __iomem *base_second;
17659dfa54cSAmit Daniel Kachhap 	int irq;
17759dfa54cSAmit Daniel Kachhap 	enum soc_type soc;
17859dfa54cSAmit Daniel Kachhap 	struct mutex lock;
1796c247393SAbhilash Kesavan 	struct clk *clk, *clk_sec, *sclk;
180199b3e3cSBartlomiej Zolnierkiewicz 	u32 cal_type;
181e3ed3649SBartlomiej Zolnierkiewicz 	u32 efuse_value;
182e3ed3649SBartlomiej Zolnierkiewicz 	u32 min_efuse_value;
183e3ed3649SBartlomiej Zolnierkiewicz 	u32 max_efuse_value;
1846c247393SAbhilash Kesavan 	u16 temp_error1, temp_error2;
185fccfe099SBartlomiej Zolnierkiewicz 	u8 gain;
18661020d18SBartlomiej Zolnierkiewicz 	u8 reference_voltage;
1873b6a1a80SLukasz Majewski 	struct thermal_zone_device *tzd;
18888fc6f73SMarek Szyprowski 	bool enabled;
1893b6a1a80SLukasz Majewski 
1905314b154SMateusz Majewski 	void (*tmu_set_low_temp)(struct exynos_tmu_data *data, u8 temp);
1915314b154SMateusz Majewski 	void (*tmu_set_high_temp)(struct exynos_tmu_data *data, u8 temp);
1925314b154SMateusz Majewski 	void (*tmu_set_crit_temp)(struct exynos_tmu_data *data, u8 temp);
1935314b154SMateusz Majewski 	void (*tmu_disable_low)(struct exynos_tmu_data *data);
1945314b154SMateusz Majewski 	void (*tmu_disable_high)(struct exynos_tmu_data *data);
195c35268f5SBartlomiej Zolnierkiewicz 	void (*tmu_initialize)(struct platform_device *pdev);
19637f9034fSBartlomiej Zolnierkiewicz 	void (*tmu_control)(struct platform_device *pdev, bool on);
197b79985caSBartlomiej Zolnierkiewicz 	int (*tmu_read)(struct exynos_tmu_data *data);
19817e8351aSSascha Hauer 	void (*tmu_set_emulation)(struct exynos_tmu_data *data, int temp);
199a7331f72SBartlomiej Zolnierkiewicz 	void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
20059dfa54cSAmit Daniel Kachhap };
20159dfa54cSAmit Daniel Kachhap 
20259dfa54cSAmit Daniel Kachhap /*
20359dfa54cSAmit Daniel Kachhap  * TMU treats temperature as a mapped temperature code.
20459dfa54cSAmit Daniel Kachhap  * The temperature is converted differently depending on the calibration type.
20559dfa54cSAmit Daniel Kachhap  */
temp_to_code(struct exynos_tmu_data * data,u8 temp)20659dfa54cSAmit Daniel Kachhap static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
20759dfa54cSAmit Daniel Kachhap {
208199b3e3cSBartlomiej Zolnierkiewicz 	if (data->cal_type == TYPE_ONE_POINT_TRIMMING)
209718b4ca1SBartlomiej Zolnierkiewicz 		return temp + data->temp_error1 - EXYNOS_FIRST_POINT_TRIM;
21059dfa54cSAmit Daniel Kachhap 
211718b4ca1SBartlomiej Zolnierkiewicz 	return (temp - EXYNOS_FIRST_POINT_TRIM) *
21259dfa54cSAmit Daniel Kachhap 		(data->temp_error2 - data->temp_error1) /
213718b4ca1SBartlomiej Zolnierkiewicz 		(EXYNOS_SECOND_POINT_TRIM - EXYNOS_FIRST_POINT_TRIM) +
214bb34b4c8SAmit Daniel Kachhap 		data->temp_error1;
21559dfa54cSAmit Daniel Kachhap }
21659dfa54cSAmit Daniel Kachhap 
21759dfa54cSAmit Daniel Kachhap /*
21859dfa54cSAmit Daniel Kachhap  * Calculate a temperature value from a temperature code.
21959dfa54cSAmit Daniel Kachhap  * The unit of the temperature is degree Celsius.
22059dfa54cSAmit Daniel Kachhap  */
code_to_temp(struct exynos_tmu_data * data,u16 temp_code)2216c247393SAbhilash Kesavan static int code_to_temp(struct exynos_tmu_data *data, u16 temp_code)
22259dfa54cSAmit Daniel Kachhap {
223199b3e3cSBartlomiej Zolnierkiewicz 	if (data->cal_type == TYPE_ONE_POINT_TRIMMING)
224718b4ca1SBartlomiej Zolnierkiewicz 		return temp_code - data->temp_error1 + EXYNOS_FIRST_POINT_TRIM;
22559dfa54cSAmit Daniel Kachhap 
2269c933b1bSBartlomiej Zolnierkiewicz 	return (temp_code - data->temp_error1) *
227718b4ca1SBartlomiej Zolnierkiewicz 		(EXYNOS_SECOND_POINT_TRIM - EXYNOS_FIRST_POINT_TRIM) /
228bb34b4c8SAmit Daniel Kachhap 		(data->temp_error2 - data->temp_error1) +
229718b4ca1SBartlomiej Zolnierkiewicz 		EXYNOS_FIRST_POINT_TRIM;
23059dfa54cSAmit Daniel Kachhap }
23159dfa54cSAmit Daniel Kachhap 
sanitize_temp_error(struct exynos_tmu_data * data,u32 trim_info)2328328a4b1SBartlomiej Zolnierkiewicz static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info)
233b835ced1SBartlomiej Zolnierkiewicz {
234aef27b65SBartlomiej Zolnierkiewicz 	u16 tmu_temp_mask =
235aef27b65SBartlomiej Zolnierkiewicz 		(data->soc == SOC_ARCH_EXYNOS7) ? EXYNOS7_TMU_TEMP_MASK
236aef27b65SBartlomiej Zolnierkiewicz 						: EXYNOS_TMU_TEMP_MASK;
23759dfa54cSAmit Daniel Kachhap 
238aef27b65SBartlomiej Zolnierkiewicz 	data->temp_error1 = trim_info & tmu_temp_mask;
23999d67fb9SBartlomiej Zolnierkiewicz 	data->temp_error2 = ((trim_info >> EXYNOS_TRIMINFO_85_SHIFT) &
240b8d582b9SAmit Daniel Kachhap 				EXYNOS_TMU_TEMP_MASK);
24159dfa54cSAmit Daniel Kachhap 
2425000806cSAmit Daniel Kachhap 	if (!data->temp_error1 ||
243e3ed3649SBartlomiej Zolnierkiewicz 	    (data->min_efuse_value > data->temp_error1) ||
244e3ed3649SBartlomiej Zolnierkiewicz 	    (data->temp_error1 > data->max_efuse_value))
245e3ed3649SBartlomiej Zolnierkiewicz 		data->temp_error1 = data->efuse_value & EXYNOS_TMU_TEMP_MASK;
2465000806cSAmit Daniel Kachhap 
2475000806cSAmit Daniel Kachhap 	if (!data->temp_error2)
2485000806cSAmit Daniel Kachhap 		data->temp_error2 =
249e3ed3649SBartlomiej Zolnierkiewicz 			(data->efuse_value >> EXYNOS_TRIMINFO_85_SHIFT) &
2505000806cSAmit Daniel Kachhap 			EXYNOS_TMU_TEMP_MASK;
2518328a4b1SBartlomiej Zolnierkiewicz }
25259dfa54cSAmit Daniel Kachhap 
exynos_tmu_initialize(struct platform_device * pdev)25359dfa54cSAmit Daniel Kachhap static int exynos_tmu_initialize(struct platform_device *pdev)
25459dfa54cSAmit Daniel Kachhap {
25559dfa54cSAmit Daniel Kachhap 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
25697b3881bSBartlomiej Zolnierkiewicz 	unsigned int status;
257b72ba67bSMateusz Majewski 	int ret = 0;
2583a3a5f15SKrzysztof Kozlowski 
25959dfa54cSAmit Daniel Kachhap 	mutex_lock(&data->lock);
26059dfa54cSAmit Daniel Kachhap 	clk_enable(data->clk);
26159dfa54cSAmit Daniel Kachhap 	if (!IS_ERR(data->clk_sec))
26259dfa54cSAmit Daniel Kachhap 		clk_enable(data->clk_sec);
26397b3881bSBartlomiej Zolnierkiewicz 
26497b3881bSBartlomiej Zolnierkiewicz 	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
265fac36bacSBartlomiej Zolnierkiewicz 	if (!status) {
26697b3881bSBartlomiej Zolnierkiewicz 		ret = -EBUSY;
267fac36bacSBartlomiej Zolnierkiewicz 	} else {
268c35268f5SBartlomiej Zolnierkiewicz 		data->tmu_initialize(pdev);
269b72ba67bSMateusz Majewski 		data->tmu_clear_irqs(data);
270b72ba67bSMateusz Majewski 	}
271b72ba67bSMateusz Majewski 
272b72ba67bSMateusz Majewski 	if (!IS_ERR(data->clk_sec))
273b72ba67bSMateusz Majewski 		clk_disable(data->clk_sec);
274b72ba67bSMateusz Majewski 	clk_disable(data->clk);
275b72ba67bSMateusz Majewski 	mutex_unlock(&data->lock);
276b72ba67bSMateusz Majewski 
277b72ba67bSMateusz Majewski 	return ret;
278b72ba67bSMateusz Majewski }
279b72ba67bSMateusz Majewski 
exynos_thermal_zone_configure(struct platform_device * pdev)280b72ba67bSMateusz Majewski static int exynos_thermal_zone_configure(struct platform_device *pdev)
281b72ba67bSMateusz Majewski {
282b72ba67bSMateusz Majewski 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
283b72ba67bSMateusz Majewski 	struct thermal_zone_device *tzd = data->tzd;
2845314b154SMateusz Majewski 	int ret, temp;
285b72ba67bSMateusz Majewski 
286b72ba67bSMateusz Majewski 	ret = thermal_zone_get_crit_temp(tzd, &temp);
2875314b154SMateusz Majewski 	if (ret) {
2885314b154SMateusz Majewski 		/* FIXME: Remove this special case */
2895314b154SMateusz Majewski 		if (data->soc == SOC_ARCH_EXYNOS5433)
2905314b154SMateusz Majewski 			return 0;
291b72ba67bSMateusz Majewski 
292b72ba67bSMateusz Majewski 		dev_err(&pdev->dev,
293b72ba67bSMateusz Majewski 			"No CRITICAL trip point defined in device tree!\n");
2945314b154SMateusz Majewski 		return ret;
295b72ba67bSMateusz Majewski 	}
296b72ba67bSMateusz Majewski 
297b72ba67bSMateusz Majewski 	mutex_lock(&data->lock);
298b72ba67bSMateusz Majewski 	clk_enable(data->clk);
299b72ba67bSMateusz Majewski 
3005314b154SMateusz Majewski 	data->tmu_set_crit_temp(data, temp / MCELSIUS);
301c8f8f768SBartlomiej Zolnierkiewicz 
30259dfa54cSAmit Daniel Kachhap 	clk_disable(data->clk);
30359dfa54cSAmit Daniel Kachhap 	mutex_unlock(&data->lock);
3045314b154SMateusz Majewski 
3055314b154SMateusz Majewski 	return 0;
30659dfa54cSAmit Daniel Kachhap }
30759dfa54cSAmit Daniel Kachhap 
get_con_reg(struct exynos_tmu_data * data,u32 con)308d00671c3SBartlomiej Zolnierkiewicz static u32 get_con_reg(struct exynos_tmu_data *data, u32 con)
30959dfa54cSAmit Daniel Kachhap {
3107575983cSBartlomiej Zolnierkiewicz 	if (data->soc == SOC_ARCH_EXYNOS4412 ||
3117575983cSBartlomiej Zolnierkiewicz 	    data->soc == SOC_ARCH_EXYNOS3250)
3127575983cSBartlomiej Zolnierkiewicz 		con |= (EXYNOS4412_MUX_ADDR_VALUE << EXYNOS4412_MUX_ADDR_SHIFT);
31386f5362eSLukasz Majewski 
31499d67fb9SBartlomiej Zolnierkiewicz 	con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK << EXYNOS_TMU_REF_VOLTAGE_SHIFT);
31561020d18SBartlomiej Zolnierkiewicz 	con |= data->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT;
316d0a0ce3eSAmit Daniel Kachhap 
31799d67fb9SBartlomiej Zolnierkiewicz 	con &= ~(EXYNOS_TMU_BUF_SLOPE_SEL_MASK << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT);
318fccfe099SBartlomiej Zolnierkiewicz 	con |= (data->gain << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT);
319d0a0ce3eSAmit Daniel Kachhap 
320b9504a6aSBartlomiej Zolnierkiewicz 	con &= ~(EXYNOS_TMU_TRIP_MODE_MASK << EXYNOS_TMU_TRIP_MODE_SHIFT);
32109d29426SBartlomiej Zolnierkiewicz 	con |= (EXYNOS_NOISE_CANCEL_MODE << EXYNOS_TMU_TRIP_MODE_SHIFT);
32259dfa54cSAmit Daniel Kachhap 
323d00671c3SBartlomiej Zolnierkiewicz 	return con;
324d00671c3SBartlomiej Zolnierkiewicz }
325d00671c3SBartlomiej Zolnierkiewicz 
exynos_tmu_control(struct platform_device * pdev,bool on)326d00671c3SBartlomiej Zolnierkiewicz static void exynos_tmu_control(struct platform_device *pdev, bool on)
327d00671c3SBartlomiej Zolnierkiewicz {
328d00671c3SBartlomiej Zolnierkiewicz 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
329d00671c3SBartlomiej Zolnierkiewicz 
330d00671c3SBartlomiej Zolnierkiewicz 	mutex_lock(&data->lock);
331d00671c3SBartlomiej Zolnierkiewicz 	clk_enable(data->clk);
33237f9034fSBartlomiej Zolnierkiewicz 	data->tmu_control(pdev, on);
33388fc6f73SMarek Szyprowski 	data->enabled = on;
33459dfa54cSAmit Daniel Kachhap 	clk_disable(data->clk);
33559dfa54cSAmit Daniel Kachhap 	mutex_unlock(&data->lock);
33659dfa54cSAmit Daniel Kachhap }
33759dfa54cSAmit Daniel Kachhap 
exynos_tmu_update_bit(struct exynos_tmu_data * data,int reg_off,int bit_off,bool enable)3385314b154SMateusz Majewski static void exynos_tmu_update_bit(struct exynos_tmu_data *data, int reg_off,
3395314b154SMateusz Majewski 				  int bit_off, bool enable)
34072d1100bSBartlomiej Zolnierkiewicz {
3415314b154SMateusz Majewski 	u32 interrupt_en;
3425314b154SMateusz Majewski 
3435314b154SMateusz Majewski 	interrupt_en = readl(data->base + reg_off);
3445314b154SMateusz Majewski 	if (enable)
3455314b154SMateusz Majewski 		interrupt_en |= BIT(bit_off);
3465314b154SMateusz Majewski 	else
3475314b154SMateusz Majewski 		interrupt_en &= ~BIT(bit_off);
3485314b154SMateusz Majewski 	writel(interrupt_en, data->base + reg_off);
349a503a10fSBartlomiej Zolnierkiewicz }
350a503a10fSBartlomiej Zolnierkiewicz 
exynos_tmu_update_temp(struct exynos_tmu_data * data,int reg_off,int bit_off,u8 temp)3515314b154SMateusz Majewski static void exynos_tmu_update_temp(struct exynos_tmu_data *data, int reg_off,
3525314b154SMateusz Majewski 				   int bit_off, u8 temp)
353c8f8f768SBartlomiej Zolnierkiewicz {
3545314b154SMateusz Majewski 	u16 tmu_temp_mask;
3555314b154SMateusz Majewski 	u32 th;
3565314b154SMateusz Majewski 
3575314b154SMateusz Majewski 	tmu_temp_mask =
3585314b154SMateusz Majewski 		(data->soc == SOC_ARCH_EXYNOS7) ? EXYNOS7_TMU_TEMP_MASK
3595314b154SMateusz Majewski 						: EXYNOS_TMU_TEMP_MASK;
3605314b154SMateusz Majewski 
3615314b154SMateusz Majewski 	th = readl(data->base + reg_off);
3625314b154SMateusz Majewski 	th &= ~(tmu_temp_mask << bit_off);
3635314b154SMateusz Majewski 	th |= temp_to_code(data, temp) << bit_off;
3645314b154SMateusz Majewski 	writel(th, data->base + reg_off);
3655314b154SMateusz Majewski }
3665314b154SMateusz Majewski 
exynos4210_tmu_set_low_temp(struct exynos_tmu_data * data,u8 temp)3675314b154SMateusz Majewski static void exynos4210_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp)
3685314b154SMateusz Majewski {
3695314b154SMateusz Majewski 	/*
3705314b154SMateusz Majewski 	 * Failing thresholds are not supported on Exynos 4210.
3715314b154SMateusz Majewski 	 * We use polling instead.
3725314b154SMateusz Majewski 	 */
3735314b154SMateusz Majewski }
3745314b154SMateusz Majewski 
exynos4210_tmu_set_high_temp(struct exynos_tmu_data * data,u8 temp)3755314b154SMateusz Majewski static void exynos4210_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp)
3765314b154SMateusz Majewski {
3775314b154SMateusz Majewski 	temp = temp_to_code(data, temp);
3785314b154SMateusz Majewski 	writeb(temp, data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + 4);
3795314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN,
3805314b154SMateusz Majewski 			      EXYNOS_TMU_INTEN_RISE0_SHIFT + 4, true);
3815314b154SMateusz Majewski }
3825314b154SMateusz Majewski 
exynos4210_tmu_disable_low(struct exynos_tmu_data * data)3835314b154SMateusz Majewski static void exynos4210_tmu_disable_low(struct exynos_tmu_data *data)
3845314b154SMateusz Majewski {
3855314b154SMateusz Majewski 	/* Again, this is handled by polling. */
3865314b154SMateusz Majewski }
3875314b154SMateusz Majewski 
exynos4210_tmu_disable_high(struct exynos_tmu_data * data)3885314b154SMateusz Majewski static void exynos4210_tmu_disable_high(struct exynos_tmu_data *data)
3895314b154SMateusz Majewski {
3905314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN,
3915314b154SMateusz Majewski 			      EXYNOS_TMU_INTEN_RISE0_SHIFT + 4, false);
3925314b154SMateusz Majewski }
3935314b154SMateusz Majewski 
exynos4210_tmu_set_crit_temp(struct exynos_tmu_data * data,u8 temp)3945314b154SMateusz Majewski static void exynos4210_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp)
3955314b154SMateusz Majewski {
3965314b154SMateusz Majewski 	/*
3975314b154SMateusz Majewski 	 * Hardware critical temperature handling is not supported on Exynos 4210.
3985314b154SMateusz Majewski 	 * We still set the critical temperature threshold, but this is only to
3995314b154SMateusz Majewski 	 * make sure it is handled as soon as possible. It is just a normal interrupt.
4005314b154SMateusz Majewski 	 */
4015314b154SMateusz Majewski 
4025314b154SMateusz Majewski 	temp = temp_to_code(data, temp);
4035314b154SMateusz Majewski 	writeb(temp, data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + 12);
4045314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN,
4055314b154SMateusz Majewski 			      EXYNOS_TMU_INTEN_RISE0_SHIFT + 12, true);
406c8f8f768SBartlomiej Zolnierkiewicz }
407c8f8f768SBartlomiej Zolnierkiewicz 
exynos4210_tmu_initialize(struct platform_device * pdev)408c35268f5SBartlomiej Zolnierkiewicz static void exynos4210_tmu_initialize(struct platform_device *pdev)
40972d1100bSBartlomiej Zolnierkiewicz {
41072d1100bSBartlomiej Zolnierkiewicz 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
41172d1100bSBartlomiej Zolnierkiewicz 
41272d1100bSBartlomiej Zolnierkiewicz 	sanitize_temp_error(data, readl(data->base + EXYNOS_TMU_REG_TRIMINFO));
413d7a5b431SMateusz Majewski 
414d7a5b431SMateusz Majewski 	writeb(0, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
41572d1100bSBartlomiej Zolnierkiewicz }
41672d1100bSBartlomiej Zolnierkiewicz 
exynos4412_tmu_set_low_temp(struct exynos_tmu_data * data,u8 temp)4175314b154SMateusz Majewski static void exynos4412_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp)
418a503a10fSBartlomiej Zolnierkiewicz {
4195314b154SMateusz Majewski 	exynos_tmu_update_temp(data, EXYNOS_THD_TEMP_FALL, 0, temp);
4205314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN,
4215314b154SMateusz Majewski 			      EXYNOS_TMU_INTEN_FALL0_SHIFT, true);
422a503a10fSBartlomiej Zolnierkiewicz }
423a503a10fSBartlomiej Zolnierkiewicz 
exynos4412_tmu_set_high_temp(struct exynos_tmu_data * data,u8 temp)4245314b154SMateusz Majewski static void exynos4412_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp)
425a503a10fSBartlomiej Zolnierkiewicz {
4265314b154SMateusz Majewski 	exynos_tmu_update_temp(data, EXYNOS_THD_TEMP_RISE, 8, temp);
4275314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN,
4285314b154SMateusz Majewski 			      EXYNOS_TMU_INTEN_RISE0_SHIFT + 4, true);
4295314b154SMateusz Majewski }
430a503a10fSBartlomiej Zolnierkiewicz 
exynos4412_tmu_disable_low(struct exynos_tmu_data * data)4315314b154SMateusz Majewski static void exynos4412_tmu_disable_low(struct exynos_tmu_data *data)
4325314b154SMateusz Majewski {
4335314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN,
4345314b154SMateusz Majewski 			      EXYNOS_TMU_INTEN_FALL0_SHIFT, false);
4355314b154SMateusz Majewski }
4365314b154SMateusz Majewski 
exynos4412_tmu_set_crit_temp(struct exynos_tmu_data * data,u8 temp)4375314b154SMateusz Majewski static void exynos4412_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp)
4385314b154SMateusz Majewski {
4395314b154SMateusz Majewski 	exynos_tmu_update_temp(data, EXYNOS_THD_TEMP_RISE, 24, temp);
4405314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS_TMU_REG_CONTROL,
4415314b154SMateusz Majewski 			      EXYNOS_TMU_THERM_TRIP_EN_SHIFT, true);
442a503a10fSBartlomiej Zolnierkiewicz }
443a503a10fSBartlomiej Zolnierkiewicz 
exynos4412_tmu_initialize(struct platform_device * pdev)444c35268f5SBartlomiej Zolnierkiewicz static void exynos4412_tmu_initialize(struct platform_device *pdev)
44572d1100bSBartlomiej Zolnierkiewicz {
44672d1100bSBartlomiej Zolnierkiewicz 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
447a503a10fSBartlomiej Zolnierkiewicz 	unsigned int trim_info, ctrl;
44872d1100bSBartlomiej Zolnierkiewicz 
44972d1100bSBartlomiej Zolnierkiewicz 	if (data->soc == SOC_ARCH_EXYNOS3250 ||
45072d1100bSBartlomiej Zolnierkiewicz 	    data->soc == SOC_ARCH_EXYNOS4412 ||
45172d1100bSBartlomiej Zolnierkiewicz 	    data->soc == SOC_ARCH_EXYNOS5250) {
45272d1100bSBartlomiej Zolnierkiewicz 		if (data->soc == SOC_ARCH_EXYNOS3250) {
45372d1100bSBartlomiej Zolnierkiewicz 			ctrl = readl(data->base + EXYNOS_TMU_TRIMINFO_CON1);
45472d1100bSBartlomiej Zolnierkiewicz 			ctrl |= EXYNOS_TRIMINFO_RELOAD_ENABLE;
45572d1100bSBartlomiej Zolnierkiewicz 			writel(ctrl, data->base + EXYNOS_TMU_TRIMINFO_CON1);
45672d1100bSBartlomiej Zolnierkiewicz 		}
45772d1100bSBartlomiej Zolnierkiewicz 		ctrl = readl(data->base + EXYNOS_TMU_TRIMINFO_CON2);
45872d1100bSBartlomiej Zolnierkiewicz 		ctrl |= EXYNOS_TRIMINFO_RELOAD_ENABLE;
45972d1100bSBartlomiej Zolnierkiewicz 		writel(ctrl, data->base + EXYNOS_TMU_TRIMINFO_CON2);
46072d1100bSBartlomiej Zolnierkiewicz 	}
46172d1100bSBartlomiej Zolnierkiewicz 
46272d1100bSBartlomiej Zolnierkiewicz 	/* On exynos5420 the triminfo register is in the shared space */
46372d1100bSBartlomiej Zolnierkiewicz 	if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO)
46472d1100bSBartlomiej Zolnierkiewicz 		trim_info = readl(data->base_second + EXYNOS_TMU_REG_TRIMINFO);
46572d1100bSBartlomiej Zolnierkiewicz 	else
46672d1100bSBartlomiej Zolnierkiewicz 		trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
46772d1100bSBartlomiej Zolnierkiewicz 
46872d1100bSBartlomiej Zolnierkiewicz 	sanitize_temp_error(data, trim_info);
4693b6a1a80SLukasz Majewski }
4703b6a1a80SLukasz Majewski 
exynos5433_tmu_set_low_temp(struct exynos_tmu_data * data,u8 temp)4715314b154SMateusz Majewski static void exynos5433_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp)
472a503a10fSBartlomiej Zolnierkiewicz {
4735314b154SMateusz Majewski 	exynos_tmu_update_temp(data, EXYNOS5433_THD_TEMP_FALL3_0, 0, temp);
4745314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN,
4755314b154SMateusz Majewski 			      EXYNOS_TMU_INTEN_FALL0_SHIFT, true);
4763b6a1a80SLukasz Majewski }
4773b6a1a80SLukasz Majewski 
exynos5433_tmu_set_high_temp(struct exynos_tmu_data * data,u8 temp)4785314b154SMateusz Majewski static void exynos5433_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp)
479a503a10fSBartlomiej Zolnierkiewicz {
4805314b154SMateusz Majewski 	exynos_tmu_update_temp(data, EXYNOS5433_THD_TEMP_RISE3_0, 8, temp);
4815314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN,
4825314b154SMateusz Majewski 			      EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, true);
483a503a10fSBartlomiej Zolnierkiewicz }
484a503a10fSBartlomiej Zolnierkiewicz 
exynos5433_tmu_disable_low(struct exynos_tmu_data * data)4855314b154SMateusz Majewski static void exynos5433_tmu_disable_low(struct exynos_tmu_data *data)
4865314b154SMateusz Majewski {
4875314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN,
4885314b154SMateusz Majewski 			      EXYNOS_TMU_INTEN_FALL0_SHIFT, false);
4895314b154SMateusz Majewski }
4905314b154SMateusz Majewski 
exynos5433_tmu_disable_high(struct exynos_tmu_data * data)4915314b154SMateusz Majewski static void exynos5433_tmu_disable_high(struct exynos_tmu_data *data)
4925314b154SMateusz Majewski {
4935314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN,
4945314b154SMateusz Majewski 			      EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, false);
4955314b154SMateusz Majewski }
4965314b154SMateusz Majewski 
exynos5433_tmu_set_crit_temp(struct exynos_tmu_data * data,u8 temp)4975314b154SMateusz Majewski static void exynos5433_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp)
4985314b154SMateusz Majewski {
4995314b154SMateusz Majewski 	exynos_tmu_update_temp(data, EXYNOS5433_THD_TEMP_RISE7_4, 24, temp);
5005314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS_TMU_REG_CONTROL,
5015314b154SMateusz Majewski 			      EXYNOS_TMU_THERM_TRIP_EN_SHIFT, true);
5025314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN,
5035314b154SMateusz Majewski 			      EXYNOS7_TMU_INTEN_RISE0_SHIFT + 7, true);
50472d1100bSBartlomiej Zolnierkiewicz }
50572d1100bSBartlomiej Zolnierkiewicz 
exynos5433_tmu_initialize(struct platform_device * pdev)506c35268f5SBartlomiej Zolnierkiewicz static void exynos5433_tmu_initialize(struct platform_device *pdev)
507488c7455SChanwoo Choi {
508488c7455SChanwoo Choi 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
50997b3881bSBartlomiej Zolnierkiewicz 	unsigned int trim_info;
510c8f8f768SBartlomiej Zolnierkiewicz 	int sensor_id, cal_type;
511488c7455SChanwoo Choi 
512488c7455SChanwoo Choi 	trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
513488c7455SChanwoo Choi 	sanitize_temp_error(data, trim_info);
514488c7455SChanwoo Choi 
515488c7455SChanwoo Choi 	/* Read the temperature sensor id */
516488c7455SChanwoo Choi 	sensor_id = (trim_info & EXYNOS5433_TRIMINFO_SENSOR_ID_MASK)
517488c7455SChanwoo Choi 				>> EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT;
518488c7455SChanwoo Choi 	dev_info(&pdev->dev, "Temperature sensor ID: 0x%x\n", sensor_id);
519488c7455SChanwoo Choi 
520488c7455SChanwoo Choi 	/* Read the calibration mode */
521488c7455SChanwoo Choi 	writel(trim_info, data->base + EXYNOS_TMU_REG_TRIMINFO);
522488c7455SChanwoo Choi 	cal_type = (trim_info & EXYNOS5433_TRIMINFO_CALIB_SEL_MASK)
523488c7455SChanwoo Choi 				>> EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT;
524488c7455SChanwoo Choi 
525488c7455SChanwoo Choi 	switch (cal_type) {
526488c7455SChanwoo Choi 	case EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING:
527199b3e3cSBartlomiej Zolnierkiewicz 		data->cal_type = TYPE_TWO_POINT_TRIMMING;
528488c7455SChanwoo Choi 		break;
529199b3e3cSBartlomiej Zolnierkiewicz 	case EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING:
530488c7455SChanwoo Choi 	default:
531199b3e3cSBartlomiej Zolnierkiewicz 		data->cal_type = TYPE_ONE_POINT_TRIMMING;
532488c7455SChanwoo Choi 		break;
533baba1ebbSKrzysztof Kozlowski 	}
534488c7455SChanwoo Choi 
535488c7455SChanwoo Choi 	dev_info(&pdev->dev, "Calibration type is %d-point calibration\n",
536488c7455SChanwoo Choi 			cal_type ?  2 : 1);
537488c7455SChanwoo Choi }
538488c7455SChanwoo Choi 
exynos7_tmu_set_low_temp(struct exynos_tmu_data * data,u8 temp)5395314b154SMateusz Majewski static void exynos7_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp)
54072d1100bSBartlomiej Zolnierkiewicz {
5415314b154SMateusz Majewski 	exynos_tmu_update_temp(data, EXYNOS7_THD_TEMP_FALL7_6 + 12, 0, temp);
5425314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
5435314b154SMateusz Majewski 			      EXYNOS_TMU_INTEN_FALL0_SHIFT + 0, true);
5446c247393SAbhilash Kesavan }
5456c247393SAbhilash Kesavan 
exynos7_tmu_set_high_temp(struct exynos_tmu_data * data,u8 temp)5465314b154SMateusz Majewski static void exynos7_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp)
547a503a10fSBartlomiej Zolnierkiewicz {
5485314b154SMateusz Majewski 	exynos_tmu_update_temp(data, EXYNOS7_THD_TEMP_RISE7_6 + 12, 16, temp);
5495314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
5505314b154SMateusz Majewski 			      EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, true);
5515314b154SMateusz Majewski }
552a503a10fSBartlomiej Zolnierkiewicz 
exynos7_tmu_disable_low(struct exynos_tmu_data * data)5535314b154SMateusz Majewski static void exynos7_tmu_disable_low(struct exynos_tmu_data *data)
5545314b154SMateusz Majewski {
5555314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
5565314b154SMateusz Majewski 			      EXYNOS_TMU_INTEN_FALL0_SHIFT + 0, false);
5575314b154SMateusz Majewski }
558a503a10fSBartlomiej Zolnierkiewicz 
exynos7_tmu_disable_high(struct exynos_tmu_data * data)5595314b154SMateusz Majewski static void exynos7_tmu_disable_high(struct exynos_tmu_data *data)
5605314b154SMateusz Majewski {
5615314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
5625314b154SMateusz Majewski 			      EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, false);
5635314b154SMateusz Majewski }
5645314b154SMateusz Majewski 
exynos7_tmu_set_crit_temp(struct exynos_tmu_data * data,u8 temp)5655314b154SMateusz Majewski static void exynos7_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp)
5665314b154SMateusz Majewski {
5675314b154SMateusz Majewski 	/*
5685314b154SMateusz Majewski 	 * Like Exynos 4210, Exynos 7 does not seem to support critical temperature
5695314b154SMateusz Majewski 	 * handling in hardware. Again, we still set a separate interrupt for it.
5705314b154SMateusz Majewski 	 */
5715314b154SMateusz Majewski 	exynos_tmu_update_temp(data, EXYNOS7_THD_TEMP_RISE7_6 + 0, 16, temp);
5725314b154SMateusz Majewski 	exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
5735314b154SMateusz Majewski 			      EXYNOS7_TMU_INTEN_RISE0_SHIFT + 7, true);
574a503a10fSBartlomiej Zolnierkiewicz }
575a503a10fSBartlomiej Zolnierkiewicz 
exynos7_tmu_initialize(struct platform_device * pdev)576c35268f5SBartlomiej Zolnierkiewicz static void exynos7_tmu_initialize(struct platform_device *pdev)
5776c247393SAbhilash Kesavan {
5786c247393SAbhilash Kesavan 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
57997b3881bSBartlomiej Zolnierkiewicz 	unsigned int trim_info;
5806c247393SAbhilash Kesavan 
5816c247393SAbhilash Kesavan 	trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
582aef27b65SBartlomiej Zolnierkiewicz 	sanitize_temp_error(data, trim_info);
5836c247393SAbhilash Kesavan }
5846c247393SAbhilash Kesavan 
exynos4210_tmu_control(struct platform_device * pdev,bool on)58537f9034fSBartlomiej Zolnierkiewicz static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
58637f9034fSBartlomiej Zolnierkiewicz {
58737f9034fSBartlomiej Zolnierkiewicz 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
5885314b154SMateusz Majewski 	unsigned int con;
58937f9034fSBartlomiej Zolnierkiewicz 
59037f9034fSBartlomiej Zolnierkiewicz 	con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));
59137f9034fSBartlomiej Zolnierkiewicz 
5925314b154SMateusz Majewski 	if (on)
593af00d488SMateusz Majewski 		con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT);
5945314b154SMateusz Majewski 	else
595af00d488SMateusz Majewski 		con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT);
59664e94192SBartlomiej Zolnierkiewicz 
59737f9034fSBartlomiej Zolnierkiewicz 	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
59837f9034fSBartlomiej Zolnierkiewicz }
59959dfa54cSAmit Daniel Kachhap 
exynos5433_tmu_control(struct platform_device * pdev,bool on)600488c7455SChanwoo Choi static void exynos5433_tmu_control(struct platform_device *pdev, bool on)
601488c7455SChanwoo Choi {
602488c7455SChanwoo Choi 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
6035314b154SMateusz Majewski 	unsigned int con, pd_det_en;
604488c7455SChanwoo Choi 
605488c7455SChanwoo Choi 	con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));
606488c7455SChanwoo Choi 
6075314b154SMateusz Majewski 	if (on)
608af00d488SMateusz Majewski 		con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT);
6095314b154SMateusz Majewski 	else
610af00d488SMateusz Majewski 		con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT);
611488c7455SChanwoo Choi 
612488c7455SChanwoo Choi 	pd_det_en = on ? EXYNOS5433_PD_DET_EN : 0;
613488c7455SChanwoo Choi 
614488c7455SChanwoo Choi 	writel(pd_det_en, data->base + EXYNOS5433_TMU_PD_DET_EN);
615488c7455SChanwoo Choi 	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
616488c7455SChanwoo Choi }
617488c7455SChanwoo Choi 
exynos7_tmu_control(struct platform_device * pdev,bool on)6186c247393SAbhilash Kesavan static void exynos7_tmu_control(struct platform_device *pdev, bool on)
6196c247393SAbhilash Kesavan {
6206c247393SAbhilash Kesavan 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
6215314b154SMateusz Majewski 	unsigned int con;
6226c247393SAbhilash Kesavan 
6236c247393SAbhilash Kesavan 	con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));
6246c247393SAbhilash Kesavan 
6256c247393SAbhilash Kesavan 	if (on) {
626af00d488SMateusz Majewski 		con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT);
627af00d488SMateusz Majewski 		con |= BIT(EXYNOS7_PD_DET_EN_SHIFT);
6286c247393SAbhilash Kesavan 	} else {
629af00d488SMateusz Majewski 		con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT);
630af00d488SMateusz Majewski 		con &= ~BIT(EXYNOS7_PD_DET_EN_SHIFT);
6316c247393SAbhilash Kesavan 	}
6326c247393SAbhilash Kesavan 
6336c247393SAbhilash Kesavan 	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
6346c247393SAbhilash Kesavan }
6356c247393SAbhilash Kesavan 
exynos_get_temp(struct thermal_zone_device * tz,int * temp)6367ea98f70SDaniel Lezcano static int exynos_get_temp(struct thermal_zone_device *tz, int *temp)
63759dfa54cSAmit Daniel Kachhap {
6385f68d078SDaniel Lezcano 	struct exynos_tmu_data *data = thermal_zone_device_priv(tz);
639c8da6cdeSMarek Szyprowski 	int value, ret = 0;
6403b6a1a80SLukasz Majewski 
6413b5236ccSMarek Szyprowski 	if (!data || !data->tmu_read)
6423b6a1a80SLukasz Majewski 		return -EINVAL;
643ffe6e16fSKrzysztof Kozlowski 	else if (!data->enabled)
644ffe6e16fSKrzysztof Kozlowski 		/*
645ffe6e16fSKrzysztof Kozlowski 		 * Called too early, probably
646ffe6e16fSKrzysztof Kozlowski 		 * from thermal_zone_of_sensor_register().
647ffe6e16fSKrzysztof Kozlowski 		 */
648ffe6e16fSKrzysztof Kozlowski 		return -EAGAIN;
64959dfa54cSAmit Daniel Kachhap 
65059dfa54cSAmit Daniel Kachhap 	mutex_lock(&data->lock);
65159dfa54cSAmit Daniel Kachhap 	clk_enable(data->clk);
6523b6a1a80SLukasz Majewski 
653c8da6cdeSMarek Szyprowski 	value = data->tmu_read(data);
654c8da6cdeSMarek Szyprowski 	if (value < 0)
655c8da6cdeSMarek Szyprowski 		ret = value;
656c8da6cdeSMarek Szyprowski 	else
657c8da6cdeSMarek Szyprowski 		*temp = code_to_temp(data, value) * MCELSIUS;
6583b6a1a80SLukasz Majewski 
65959dfa54cSAmit Daniel Kachhap 	clk_disable(data->clk);
66059dfa54cSAmit Daniel Kachhap 	mutex_unlock(&data->lock);
66159dfa54cSAmit Daniel Kachhap 
662c8da6cdeSMarek Szyprowski 	return ret;
66359dfa54cSAmit Daniel Kachhap }
66459dfa54cSAmit Daniel Kachhap 
66559dfa54cSAmit Daniel Kachhap #ifdef CONFIG_THERMAL_EMULATION
get_emul_con_reg(struct exynos_tmu_data * data,unsigned int val,int temp)666154013eaSBartlomiej Zolnierkiewicz static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val,
66717e8351aSSascha Hauer 			    int temp)
668154013eaSBartlomiej Zolnierkiewicz {
669154013eaSBartlomiej Zolnierkiewicz 	if (temp) {
670154013eaSBartlomiej Zolnierkiewicz 		temp /= MCELSIUS;
671154013eaSBartlomiej Zolnierkiewicz 
672154013eaSBartlomiej Zolnierkiewicz 		val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT);
673154013eaSBartlomiej Zolnierkiewicz 		val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT);
6746c247393SAbhilash Kesavan 		if (data->soc == SOC_ARCH_EXYNOS7) {
6756c247393SAbhilash Kesavan 			val &= ~(EXYNOS7_EMUL_DATA_MASK <<
6766c247393SAbhilash Kesavan 				EXYNOS7_EMUL_DATA_SHIFT);
6776c247393SAbhilash Kesavan 			val |= (temp_to_code(data, temp) <<
6786c247393SAbhilash Kesavan 				EXYNOS7_EMUL_DATA_SHIFT) |
679154013eaSBartlomiej Zolnierkiewicz 				EXYNOS_EMUL_ENABLE;
680154013eaSBartlomiej Zolnierkiewicz 		} else {
6816c247393SAbhilash Kesavan 			val &= ~(EXYNOS_EMUL_DATA_MASK <<
6826c247393SAbhilash Kesavan 				EXYNOS_EMUL_DATA_SHIFT);
6836c247393SAbhilash Kesavan 			val |= (temp_to_code(data, temp) <<
6846c247393SAbhilash Kesavan 				EXYNOS_EMUL_DATA_SHIFT) |
6856c247393SAbhilash Kesavan 				EXYNOS_EMUL_ENABLE;
6866c247393SAbhilash Kesavan 		}
6876c247393SAbhilash Kesavan 	} else {
688154013eaSBartlomiej Zolnierkiewicz 		val &= ~EXYNOS_EMUL_ENABLE;
689154013eaSBartlomiej Zolnierkiewicz 	}
690154013eaSBartlomiej Zolnierkiewicz 
691154013eaSBartlomiej Zolnierkiewicz 	return val;
692154013eaSBartlomiej Zolnierkiewicz }
693154013eaSBartlomiej Zolnierkiewicz 
exynos4412_tmu_set_emulation(struct exynos_tmu_data * data,int temp)694285d994aSBartlomiej Zolnierkiewicz static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data,
69517e8351aSSascha Hauer 					 int temp)
696285d994aSBartlomiej Zolnierkiewicz {
697285d994aSBartlomiej Zolnierkiewicz 	unsigned int val;
698285d994aSBartlomiej Zolnierkiewicz 	u32 emul_con;
699285d994aSBartlomiej Zolnierkiewicz 
700285d994aSBartlomiej Zolnierkiewicz 	if (data->soc == SOC_ARCH_EXYNOS5260)
701285d994aSBartlomiej Zolnierkiewicz 		emul_con = EXYNOS5260_EMUL_CON;
702b28fec13SSudip Mukherjee 	else if (data->soc == SOC_ARCH_EXYNOS5433)
703488c7455SChanwoo Choi 		emul_con = EXYNOS5433_TMU_EMUL_CON;
7046c247393SAbhilash Kesavan 	else if (data->soc == SOC_ARCH_EXYNOS7)
7056c247393SAbhilash Kesavan 		emul_con = EXYNOS7_TMU_REG_EMUL_CON;
706285d994aSBartlomiej Zolnierkiewicz 	else
707285d994aSBartlomiej Zolnierkiewicz 		emul_con = EXYNOS_EMUL_CON;
708285d994aSBartlomiej Zolnierkiewicz 
709285d994aSBartlomiej Zolnierkiewicz 	val = readl(data->base + emul_con);
710285d994aSBartlomiej Zolnierkiewicz 	val = get_emul_con_reg(data, val, temp);
711285d994aSBartlomiej Zolnierkiewicz 	writel(val, data->base + emul_con);
712285d994aSBartlomiej Zolnierkiewicz }
713285d994aSBartlomiej Zolnierkiewicz 
exynos_tmu_set_emulation(struct thermal_zone_device * tz,int temp)7147ea98f70SDaniel Lezcano static int exynos_tmu_set_emulation(struct thermal_zone_device *tz, int temp)
71559dfa54cSAmit Daniel Kachhap {
7165f68d078SDaniel Lezcano 	struct exynos_tmu_data *data = thermal_zone_device_priv(tz);
71759dfa54cSAmit Daniel Kachhap 	int ret = -EINVAL;
71859dfa54cSAmit Daniel Kachhap 
719ef3f80fcSBartlomiej Zolnierkiewicz 	if (data->soc == SOC_ARCH_EXYNOS4210)
72059dfa54cSAmit Daniel Kachhap 		goto out;
72159dfa54cSAmit Daniel Kachhap 
72259dfa54cSAmit Daniel Kachhap 	if (temp && temp < MCELSIUS)
72359dfa54cSAmit Daniel Kachhap 		goto out;
72459dfa54cSAmit Daniel Kachhap 
72559dfa54cSAmit Daniel Kachhap 	mutex_lock(&data->lock);
72659dfa54cSAmit Daniel Kachhap 	clk_enable(data->clk);
727285d994aSBartlomiej Zolnierkiewicz 	data->tmu_set_emulation(data, temp);
72859dfa54cSAmit Daniel Kachhap 	clk_disable(data->clk);
72959dfa54cSAmit Daniel Kachhap 	mutex_unlock(&data->lock);
73059dfa54cSAmit Daniel Kachhap 	return 0;
73159dfa54cSAmit Daniel Kachhap out:
73259dfa54cSAmit Daniel Kachhap 	return ret;
73359dfa54cSAmit Daniel Kachhap }
73459dfa54cSAmit Daniel Kachhap #else
735285d994aSBartlomiej Zolnierkiewicz #define exynos4412_tmu_set_emulation NULL
exynos_tmu_set_emulation(struct thermal_zone_device * tz,int temp)7367ea98f70SDaniel Lezcano static int exynos_tmu_set_emulation(struct thermal_zone_device *tz, int temp)
73759dfa54cSAmit Daniel Kachhap 	{ return -EINVAL; }
73859dfa54cSAmit Daniel Kachhap #endif /* CONFIG_THERMAL_EMULATION */
73959dfa54cSAmit Daniel Kachhap 
exynos4210_tmu_read(struct exynos_tmu_data * data)740b79985caSBartlomiej Zolnierkiewicz static int exynos4210_tmu_read(struct exynos_tmu_data *data)
741b79985caSBartlomiej Zolnierkiewicz {
742b79985caSBartlomiej Zolnierkiewicz 	int ret = readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP);
743b79985caSBartlomiej Zolnierkiewicz 
744b79985caSBartlomiej Zolnierkiewicz 	/* "temp_code" should range between 75 and 175 */
745b79985caSBartlomiej Zolnierkiewicz 	return (ret < 75 || ret > 175) ? -ENODATA : ret;
746b79985caSBartlomiej Zolnierkiewicz }
747b79985caSBartlomiej Zolnierkiewicz 
exynos4412_tmu_read(struct exynos_tmu_data * data)748b79985caSBartlomiej Zolnierkiewicz static int exynos4412_tmu_read(struct exynos_tmu_data *data)
749b79985caSBartlomiej Zolnierkiewicz {
750b79985caSBartlomiej Zolnierkiewicz 	return readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP);
751b79985caSBartlomiej Zolnierkiewicz }
752b79985caSBartlomiej Zolnierkiewicz 
exynos7_tmu_read(struct exynos_tmu_data * data)7536c247393SAbhilash Kesavan static int exynos7_tmu_read(struct exynos_tmu_data *data)
7546c247393SAbhilash Kesavan {
7556c247393SAbhilash Kesavan 	return readw(data->base + EXYNOS_TMU_REG_CURRENT_TEMP) &
7566c247393SAbhilash Kesavan 		EXYNOS7_TMU_TEMP_MASK;
7576c247393SAbhilash Kesavan }
7586c247393SAbhilash Kesavan 
exynos_tmu_threaded_irq(int irq,void * id)75920009a81SMateusz Majewski static irqreturn_t exynos_tmu_threaded_irq(int irq, void *id)
76059dfa54cSAmit Daniel Kachhap {
76120009a81SMateusz Majewski 	struct exynos_tmu_data *data = id;
762a0395eeeSAmit Daniel Kachhap 
763b43e3cfeSBartlomiej Zolnierkiewicz 	thermal_zone_device_update(data->tzd, THERMAL_EVENT_UNSPECIFIED);
764b43e3cfeSBartlomiej Zolnierkiewicz 
76559dfa54cSAmit Daniel Kachhap 	mutex_lock(&data->lock);
76659dfa54cSAmit Daniel Kachhap 	clk_enable(data->clk);
767b8d582b9SAmit Daniel Kachhap 
768a4463c4fSAmit Daniel Kachhap 	/* TODO: take action based on particular interrupt */
769a7331f72SBartlomiej Zolnierkiewicz 	data->tmu_clear_irqs(data);
770b8d582b9SAmit Daniel Kachhap 
77159dfa54cSAmit Daniel Kachhap 	clk_disable(data->clk);
77259dfa54cSAmit Daniel Kachhap 	mutex_unlock(&data->lock);
77320009a81SMateusz Majewski 
77420009a81SMateusz Majewski 	return IRQ_HANDLED;
77559dfa54cSAmit Daniel Kachhap }
77659dfa54cSAmit Daniel Kachhap 
exynos4210_tmu_clear_irqs(struct exynos_tmu_data * data)777a7331f72SBartlomiej Zolnierkiewicz static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data)
778a7331f72SBartlomiej Zolnierkiewicz {
779a7331f72SBartlomiej Zolnierkiewicz 	unsigned int val_irq;
780a7331f72SBartlomiej Zolnierkiewicz 	u32 tmu_intstat, tmu_intclear;
781a7331f72SBartlomiej Zolnierkiewicz 
782a7331f72SBartlomiej Zolnierkiewicz 	if (data->soc == SOC_ARCH_EXYNOS5260) {
783a7331f72SBartlomiej Zolnierkiewicz 		tmu_intstat = EXYNOS5260_TMU_REG_INTSTAT;
784a7331f72SBartlomiej Zolnierkiewicz 		tmu_intclear = EXYNOS5260_TMU_REG_INTCLEAR;
7856c247393SAbhilash Kesavan 	} else if (data->soc == SOC_ARCH_EXYNOS7) {
7866c247393SAbhilash Kesavan 		tmu_intstat = EXYNOS7_TMU_REG_INTPEND;
7876c247393SAbhilash Kesavan 		tmu_intclear = EXYNOS7_TMU_REG_INTPEND;
788488c7455SChanwoo Choi 	} else if (data->soc == SOC_ARCH_EXYNOS5433) {
789488c7455SChanwoo Choi 		tmu_intstat = EXYNOS5433_TMU_REG_INTPEND;
790488c7455SChanwoo Choi 		tmu_intclear = EXYNOS5433_TMU_REG_INTPEND;
791a7331f72SBartlomiej Zolnierkiewicz 	} else {
792a7331f72SBartlomiej Zolnierkiewicz 		tmu_intstat = EXYNOS_TMU_REG_INTSTAT;
793a7331f72SBartlomiej Zolnierkiewicz 		tmu_intclear = EXYNOS_TMU_REG_INTCLEAR;
794a7331f72SBartlomiej Zolnierkiewicz 	}
795a7331f72SBartlomiej Zolnierkiewicz 
796a7331f72SBartlomiej Zolnierkiewicz 	val_irq = readl(data->base + tmu_intstat);
797a7331f72SBartlomiej Zolnierkiewicz 	/*
798a7331f72SBartlomiej Zolnierkiewicz 	 * Clear the interrupts.  Please note that the documentation for
799a7331f72SBartlomiej Zolnierkiewicz 	 * Exynos3250, Exynos4412, Exynos5250 and Exynos5260 incorrectly
800a7331f72SBartlomiej Zolnierkiewicz 	 * states that INTCLEAR register has a different placing of bits
801a7331f72SBartlomiej Zolnierkiewicz 	 * responsible for FALL IRQs than INTSTAT register.  Exynos5420
802a7331f72SBartlomiej Zolnierkiewicz 	 * and Exynos5440 documentation is correct (Exynos4210 doesn't
803a7331f72SBartlomiej Zolnierkiewicz 	 * support FALL IRQs at all).
804a7331f72SBartlomiej Zolnierkiewicz 	 */
805a7331f72SBartlomiej Zolnierkiewicz 	writel(val_irq, data->base + tmu_intclear);
806a7331f72SBartlomiej Zolnierkiewicz }
807a7331f72SBartlomiej Zolnierkiewicz 
80859dfa54cSAmit Daniel Kachhap static const struct of_device_id exynos_tmu_match[] = {
809fee88e2bSMaciej Purski 	{
810fee88e2bSMaciej Purski 		.compatible = "samsung,exynos3250-tmu",
811fee88e2bSMaciej Purski 		.data = (const void *)SOC_ARCH_EXYNOS3250,
812fee88e2bSMaciej Purski 	}, {
813fee88e2bSMaciej Purski 		.compatible = "samsung,exynos4210-tmu",
814fee88e2bSMaciej Purski 		.data = (const void *)SOC_ARCH_EXYNOS4210,
815fee88e2bSMaciej Purski 	}, {
816fee88e2bSMaciej Purski 		.compatible = "samsung,exynos4412-tmu",
817fee88e2bSMaciej Purski 		.data = (const void *)SOC_ARCH_EXYNOS4412,
818fee88e2bSMaciej Purski 	}, {
819fee88e2bSMaciej Purski 		.compatible = "samsung,exynos5250-tmu",
820fee88e2bSMaciej Purski 		.data = (const void *)SOC_ARCH_EXYNOS5250,
821fee88e2bSMaciej Purski 	}, {
822fee88e2bSMaciej Purski 		.compatible = "samsung,exynos5260-tmu",
823fee88e2bSMaciej Purski 		.data = (const void *)SOC_ARCH_EXYNOS5260,
824fee88e2bSMaciej Purski 	}, {
825fee88e2bSMaciej Purski 		.compatible = "samsung,exynos5420-tmu",
826fee88e2bSMaciej Purski 		.data = (const void *)SOC_ARCH_EXYNOS5420,
827fee88e2bSMaciej Purski 	}, {
828fee88e2bSMaciej Purski 		.compatible = "samsung,exynos5420-tmu-ext-triminfo",
829fee88e2bSMaciej Purski 		.data = (const void *)SOC_ARCH_EXYNOS5420_TRIMINFO,
830fee88e2bSMaciej Purski 	}, {
831fee88e2bSMaciej Purski 		.compatible = "samsung,exynos5433-tmu",
832fee88e2bSMaciej Purski 		.data = (const void *)SOC_ARCH_EXYNOS5433,
833fee88e2bSMaciej Purski 	}, {
834fee88e2bSMaciej Purski 		.compatible = "samsung,exynos7-tmu",
835fee88e2bSMaciej Purski 		.data = (const void *)SOC_ARCH_EXYNOS7,
836fee88e2bSMaciej Purski 	},
837fee88e2bSMaciej Purski 	{ },
83859dfa54cSAmit Daniel Kachhap };
83959dfa54cSAmit Daniel Kachhap MODULE_DEVICE_TABLE(of, exynos_tmu_match);
84059dfa54cSAmit Daniel Kachhap 
exynos_map_dt_data(struct platform_device * pdev)841cebe7373SAmit Daniel Kachhap static int exynos_map_dt_data(struct platform_device *pdev)
84259dfa54cSAmit Daniel Kachhap {
843cebe7373SAmit Daniel Kachhap 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
844cebe7373SAmit Daniel Kachhap 	struct resource res;
84559dfa54cSAmit Daniel Kachhap 
84673b5b1d7SSachin Kamat 	if (!data || !pdev->dev.of_node)
847cebe7373SAmit Daniel Kachhap 		return -ENODEV;
84859dfa54cSAmit Daniel Kachhap 
849cebe7373SAmit Daniel Kachhap 	data->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
850cebe7373SAmit Daniel Kachhap 	if (data->irq <= 0) {
851cebe7373SAmit Daniel Kachhap 		dev_err(&pdev->dev, "failed to get IRQ\n");
852cebe7373SAmit Daniel Kachhap 		return -ENODEV;
853cebe7373SAmit Daniel Kachhap 	}
854cebe7373SAmit Daniel Kachhap 
855cebe7373SAmit Daniel Kachhap 	if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
856cebe7373SAmit Daniel Kachhap 		dev_err(&pdev->dev, "failed to get Resource 0\n");
857cebe7373SAmit Daniel Kachhap 		return -ENODEV;
858cebe7373SAmit Daniel Kachhap 	}
859cebe7373SAmit Daniel Kachhap 
860cebe7373SAmit Daniel Kachhap 	data->base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
861cebe7373SAmit Daniel Kachhap 	if (!data->base) {
862cebe7373SAmit Daniel Kachhap 		dev_err(&pdev->dev, "Failed to ioremap memory\n");
863cebe7373SAmit Daniel Kachhap 		return -EADDRNOTAVAIL;
864cebe7373SAmit Daniel Kachhap 	}
865cebe7373SAmit Daniel Kachhap 
8661892f9f0SKrzysztof Kozlowski 	data->soc = (uintptr_t)of_device_get_match_data(&pdev->dev);
86756adb9efSBartlomiej Zolnierkiewicz 
86856adb9efSBartlomiej Zolnierkiewicz 	switch (data->soc) {
86956adb9efSBartlomiej Zolnierkiewicz 	case SOC_ARCH_EXYNOS4210:
8705314b154SMateusz Majewski 		data->tmu_set_low_temp = exynos4210_tmu_set_low_temp;
8715314b154SMateusz Majewski 		data->tmu_set_high_temp = exynos4210_tmu_set_high_temp;
8725314b154SMateusz Majewski 		data->tmu_disable_low = exynos4210_tmu_disable_low;
8735314b154SMateusz Majewski 		data->tmu_disable_high = exynos4210_tmu_disable_high;
8745314b154SMateusz Majewski 		data->tmu_set_crit_temp = exynos4210_tmu_set_crit_temp;
87556adb9efSBartlomiej Zolnierkiewicz 		data->tmu_initialize = exynos4210_tmu_initialize;
87656adb9efSBartlomiej Zolnierkiewicz 		data->tmu_control = exynos4210_tmu_control;
87756adb9efSBartlomiej Zolnierkiewicz 		data->tmu_read = exynos4210_tmu_read;
87856adb9efSBartlomiej Zolnierkiewicz 		data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
879fccfe099SBartlomiej Zolnierkiewicz 		data->gain = 15;
88061020d18SBartlomiej Zolnierkiewicz 		data->reference_voltage = 7;
881e3ed3649SBartlomiej Zolnierkiewicz 		data->efuse_value = 55;
882e3ed3649SBartlomiej Zolnierkiewicz 		data->min_efuse_value = 40;
883e3ed3649SBartlomiej Zolnierkiewicz 		data->max_efuse_value = 100;
88456adb9efSBartlomiej Zolnierkiewicz 		break;
88556adb9efSBartlomiej Zolnierkiewicz 	case SOC_ARCH_EXYNOS3250:
88656adb9efSBartlomiej Zolnierkiewicz 	case SOC_ARCH_EXYNOS4412:
88756adb9efSBartlomiej Zolnierkiewicz 	case SOC_ARCH_EXYNOS5250:
88856adb9efSBartlomiej Zolnierkiewicz 	case SOC_ARCH_EXYNOS5260:
88956adb9efSBartlomiej Zolnierkiewicz 	case SOC_ARCH_EXYNOS5420:
89056adb9efSBartlomiej Zolnierkiewicz 	case SOC_ARCH_EXYNOS5420_TRIMINFO:
8915314b154SMateusz Majewski 		data->tmu_set_low_temp = exynos4412_tmu_set_low_temp;
8925314b154SMateusz Majewski 		data->tmu_set_high_temp = exynos4412_tmu_set_high_temp;
8935314b154SMateusz Majewski 		data->tmu_disable_low = exynos4412_tmu_disable_low;
8945314b154SMateusz Majewski 		data->tmu_disable_high = exynos4210_tmu_disable_high;
8955314b154SMateusz Majewski 		data->tmu_set_crit_temp = exynos4412_tmu_set_crit_temp;
89656adb9efSBartlomiej Zolnierkiewicz 		data->tmu_initialize = exynos4412_tmu_initialize;
89756adb9efSBartlomiej Zolnierkiewicz 		data->tmu_control = exynos4210_tmu_control;
89856adb9efSBartlomiej Zolnierkiewicz 		data->tmu_read = exynos4412_tmu_read;
89956adb9efSBartlomiej Zolnierkiewicz 		data->tmu_set_emulation = exynos4412_tmu_set_emulation;
90056adb9efSBartlomiej Zolnierkiewicz 		data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
901fccfe099SBartlomiej Zolnierkiewicz 		data->gain = 8;
90261020d18SBartlomiej Zolnierkiewicz 		data->reference_voltage = 16;
903e3ed3649SBartlomiej Zolnierkiewicz 		data->efuse_value = 55;
904e3ed3649SBartlomiej Zolnierkiewicz 		if (data->soc != SOC_ARCH_EXYNOS5420 &&
905e3ed3649SBartlomiej Zolnierkiewicz 		    data->soc != SOC_ARCH_EXYNOS5420_TRIMINFO)
906e3ed3649SBartlomiej Zolnierkiewicz 			data->min_efuse_value = 40;
907e3ed3649SBartlomiej Zolnierkiewicz 		else
908e3ed3649SBartlomiej Zolnierkiewicz 			data->min_efuse_value = 0;
909e3ed3649SBartlomiej Zolnierkiewicz 		data->max_efuse_value = 100;
91056adb9efSBartlomiej Zolnierkiewicz 		break;
911488c7455SChanwoo Choi 	case SOC_ARCH_EXYNOS5433:
9125314b154SMateusz Majewski 		data->tmu_set_low_temp = exynos5433_tmu_set_low_temp;
9135314b154SMateusz Majewski 		data->tmu_set_high_temp = exynos5433_tmu_set_high_temp;
9145314b154SMateusz Majewski 		data->tmu_disable_low = exynos5433_tmu_disable_low;
9155314b154SMateusz Majewski 		data->tmu_disable_high = exynos5433_tmu_disable_high;
9165314b154SMateusz Majewski 		data->tmu_set_crit_temp = exynos5433_tmu_set_crit_temp;
917488c7455SChanwoo Choi 		data->tmu_initialize = exynos5433_tmu_initialize;
918488c7455SChanwoo Choi 		data->tmu_control = exynos5433_tmu_control;
919488c7455SChanwoo Choi 		data->tmu_read = exynos4412_tmu_read;
920488c7455SChanwoo Choi 		data->tmu_set_emulation = exynos4412_tmu_set_emulation;
921488c7455SChanwoo Choi 		data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
922fccfe099SBartlomiej Zolnierkiewicz 		data->gain = 8;
92361020d18SBartlomiej Zolnierkiewicz 		if (res.start == EXYNOS5433_G3D_BASE)
92461020d18SBartlomiej Zolnierkiewicz 			data->reference_voltage = 23;
92561020d18SBartlomiej Zolnierkiewicz 		else
92661020d18SBartlomiej Zolnierkiewicz 			data->reference_voltage = 16;
927e3ed3649SBartlomiej Zolnierkiewicz 		data->efuse_value = 75;
928e3ed3649SBartlomiej Zolnierkiewicz 		data->min_efuse_value = 40;
929e3ed3649SBartlomiej Zolnierkiewicz 		data->max_efuse_value = 150;
93056adb9efSBartlomiej Zolnierkiewicz 		break;
9316c247393SAbhilash Kesavan 	case SOC_ARCH_EXYNOS7:
9325314b154SMateusz Majewski 		data->tmu_set_low_temp = exynos7_tmu_set_low_temp;
9335314b154SMateusz Majewski 		data->tmu_set_high_temp = exynos7_tmu_set_high_temp;
9345314b154SMateusz Majewski 		data->tmu_disable_low = exynos7_tmu_disable_low;
9355314b154SMateusz Majewski 		data->tmu_disable_high = exynos7_tmu_disable_high;
9365314b154SMateusz Majewski 		data->tmu_set_crit_temp = exynos7_tmu_set_crit_temp;
9376c247393SAbhilash Kesavan 		data->tmu_initialize = exynos7_tmu_initialize;
9386c247393SAbhilash Kesavan 		data->tmu_control = exynos7_tmu_control;
9396c247393SAbhilash Kesavan 		data->tmu_read = exynos7_tmu_read;
9406c247393SAbhilash Kesavan 		data->tmu_set_emulation = exynos4412_tmu_set_emulation;
9416c247393SAbhilash Kesavan 		data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
942fccfe099SBartlomiej Zolnierkiewicz 		data->gain = 9;
94361020d18SBartlomiej Zolnierkiewicz 		data->reference_voltage = 17;
944e3ed3649SBartlomiej Zolnierkiewicz 		data->efuse_value = 75;
945e3ed3649SBartlomiej Zolnierkiewicz 		data->min_efuse_value = 15;
946e3ed3649SBartlomiej Zolnierkiewicz 		data->max_efuse_value = 100;
9476c247393SAbhilash Kesavan 		break;
94856adb9efSBartlomiej Zolnierkiewicz 	default:
94956adb9efSBartlomiej Zolnierkiewicz 		dev_err(&pdev->dev, "Platform not supported\n");
95056adb9efSBartlomiej Zolnierkiewicz 		return -EINVAL;
95156adb9efSBartlomiej Zolnierkiewicz 	}
95256adb9efSBartlomiej Zolnierkiewicz 
953199b3e3cSBartlomiej Zolnierkiewicz 	data->cal_type = TYPE_ONE_POINT_TRIMMING;
954199b3e3cSBartlomiej Zolnierkiewicz 
955d9b6ee14SAmit Daniel Kachhap 	/*
956d9b6ee14SAmit Daniel Kachhap 	 * Check if the TMU shares some registers and then try to map the
957d9b6ee14SAmit Daniel Kachhap 	 * memory of common registers.
958d9b6ee14SAmit Daniel Kachhap 	 */
9598014220dSKrzysztof Kozlowski 	if (data->soc != SOC_ARCH_EXYNOS5420_TRIMINFO)
960d9b6ee14SAmit Daniel Kachhap 		return 0;
961d9b6ee14SAmit Daniel Kachhap 
962d9b6ee14SAmit Daniel Kachhap 	if (of_address_to_resource(pdev->dev.of_node, 1, &res)) {
963d9b6ee14SAmit Daniel Kachhap 		dev_err(&pdev->dev, "failed to get Resource 1\n");
964d9b6ee14SAmit Daniel Kachhap 		return -ENODEV;
965d9b6ee14SAmit Daniel Kachhap 	}
966d9b6ee14SAmit Daniel Kachhap 
9679025d563SNaveen Krishna Chatradhi 	data->base_second = devm_ioremap(&pdev->dev, res.start,
968d9b6ee14SAmit Daniel Kachhap 					resource_size(&res));
9699025d563SNaveen Krishna Chatradhi 	if (!data->base_second) {
970d9b6ee14SAmit Daniel Kachhap 		dev_err(&pdev->dev, "Failed to ioremap memory\n");
971d9b6ee14SAmit Daniel Kachhap 		return -ENOMEM;
972d9b6ee14SAmit Daniel Kachhap 	}
973cebe7373SAmit Daniel Kachhap 
974cebe7373SAmit Daniel Kachhap 	return 0;
975cebe7373SAmit Daniel Kachhap }
976cebe7373SAmit Daniel Kachhap 
exynos_set_trips(struct thermal_zone_device * tz,int low,int high)9775314b154SMateusz Majewski static int exynos_set_trips(struct thermal_zone_device *tz, int low, int high)
9785314b154SMateusz Majewski {
9795314b154SMateusz Majewski 	struct exynos_tmu_data *data = thermal_zone_device_priv(tz);
9805314b154SMateusz Majewski 
9815314b154SMateusz Majewski 	mutex_lock(&data->lock);
9825314b154SMateusz Majewski 	clk_enable(data->clk);
9835314b154SMateusz Majewski 
9845314b154SMateusz Majewski 	if (low > INT_MIN)
9855314b154SMateusz Majewski 		data->tmu_set_low_temp(data, low / MCELSIUS);
9865314b154SMateusz Majewski 	else
9875314b154SMateusz Majewski 		data->tmu_disable_low(data);
9885314b154SMateusz Majewski 	if (high < INT_MAX)
9895314b154SMateusz Majewski 		data->tmu_set_high_temp(data, high / MCELSIUS);
9905314b154SMateusz Majewski 	else
9915314b154SMateusz Majewski 		data->tmu_disable_high(data);
9925314b154SMateusz Majewski 
9935314b154SMateusz Majewski 	clk_disable(data->clk);
9945314b154SMateusz Majewski 	mutex_unlock(&data->lock);
9955314b154SMateusz Majewski 
9965314b154SMateusz Majewski 	return 0;
9975314b154SMateusz Majewski }
9985314b154SMateusz Majewski 
9997ea98f70SDaniel Lezcano static const struct thermal_zone_device_ops exynos_sensor_ops = {
10003b6a1a80SLukasz Majewski 	.get_temp = exynos_get_temp,
10013b6a1a80SLukasz Majewski 	.set_emul_temp = exynos_tmu_set_emulation,
10025314b154SMateusz Majewski 	.set_trips = exynos_set_trips,
10033b6a1a80SLukasz Majewski };
10043b6a1a80SLukasz Majewski 
exynos_tmu_probe(struct platform_device * pdev)1005cebe7373SAmit Daniel Kachhap static int exynos_tmu_probe(struct platform_device *pdev)
1006cebe7373SAmit Daniel Kachhap {
10074a6cf76eSKrzysztof Kozlowski 	struct device *dev = &pdev->dev;
10083b6a1a80SLukasz Majewski 	struct exynos_tmu_data *data;
10093b6a1a80SLukasz Majewski 	int ret;
1010cebe7373SAmit Daniel Kachhap 
10114a6cf76eSKrzysztof Kozlowski 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
10122a9675b3SJingoo Han 	if (!data)
101359dfa54cSAmit Daniel Kachhap 		return -ENOMEM;
101459dfa54cSAmit Daniel Kachhap 
1015cebe7373SAmit Daniel Kachhap 	platform_set_drvdata(pdev, data);
1016cebe7373SAmit Daniel Kachhap 	mutex_init(&data->lock);
1017cebe7373SAmit Daniel Kachhap 
1018824ead03SKrzysztof Kozlowski 	/*
1019824ead03SKrzysztof Kozlowski 	 * Try enabling the regulator if found
1020824ead03SKrzysztof Kozlowski 	 * TODO: Add regulator as an SOC feature, so that regulator enable
1021824ead03SKrzysztof Kozlowski 	 * is a compulsory call.
1022824ead03SKrzysztof Kozlowski 	 */
10234a6cf76eSKrzysztof Kozlowski 	ret = devm_regulator_get_enable_optional(dev, "vtmu");
102452ef6f56SMateusz Majewski 	switch (ret) {
10255d6976d0SMateusz Majewski 	case 0:
102652ef6f56SMateusz Majewski 	case -ENODEV:
102752ef6f56SMateusz Majewski 		break;
102852ef6f56SMateusz Majewski 	case -EPROBE_DEFER:
1029ccb361d2SJavier Martinez Canillas 		return -EPROBE_DEFER;
103052ef6f56SMateusz Majewski 	default:
10314a6cf76eSKrzysztof Kozlowski 		dev_err(dev, "Failed to get enabled regulator: %d\n", ret);
103252ef6f56SMateusz Majewski 		return ret;
103352ef6f56SMateusz Majewski 	}
1034824ead03SKrzysztof Kozlowski 
1035cebe7373SAmit Daniel Kachhap 	ret = exynos_map_dt_data(pdev);
1036cebe7373SAmit Daniel Kachhap 	if (ret)
10375d6976d0SMateusz Majewski 		return ret;
1038cebe7373SAmit Daniel Kachhap 
10394a6cf76eSKrzysztof Kozlowski 	data->clk = devm_clk_get(dev, "tmu_apbif");
1040*ca617669SKrzysztof Kozlowski 	if (IS_ERR(data->clk))
1041*ca617669SKrzysztof Kozlowski 		return dev_err_probe(dev, PTR_ERR(data->clk), "Failed to get clock\n");
104259dfa54cSAmit Daniel Kachhap 
10434a6cf76eSKrzysztof Kozlowski 	data->clk_sec = devm_clk_get(dev, "tmu_triminfo_apbif");
104414a11dc7SNaveen Krishna Chatradhi 	if (IS_ERR(data->clk_sec)) {
1045*ca617669SKrzysztof Kozlowski 		if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO)
1046*ca617669SKrzysztof Kozlowski 			return dev_err_probe(dev, PTR_ERR(data->clk_sec),
1047*ca617669SKrzysztof Kozlowski 					     "Failed to get triminfo clock\n");
104814a11dc7SNaveen Krishna Chatradhi 	} else {
104914a11dc7SNaveen Krishna Chatradhi 		ret = clk_prepare(data->clk_sec);
105014a11dc7SNaveen Krishna Chatradhi 		if (ret) {
10514a6cf76eSKrzysztof Kozlowski 			dev_err(dev, "Failed to get clock\n");
10525d6976d0SMateusz Majewski 			return ret;
105314a11dc7SNaveen Krishna Chatradhi 		}
105414a11dc7SNaveen Krishna Chatradhi 	}
105514a11dc7SNaveen Krishna Chatradhi 
105614a11dc7SNaveen Krishna Chatradhi 	ret = clk_prepare(data->clk);
105714a11dc7SNaveen Krishna Chatradhi 	if (ret) {
10584a6cf76eSKrzysztof Kozlowski 		dev_err(dev, "Failed to get clock\n");
105914a11dc7SNaveen Krishna Chatradhi 		goto err_clk_sec;
106014a11dc7SNaveen Krishna Chatradhi 	}
106159dfa54cSAmit Daniel Kachhap 
1062488c7455SChanwoo Choi 	switch (data->soc) {
1063488c7455SChanwoo Choi 	case SOC_ARCH_EXYNOS5433:
1064488c7455SChanwoo Choi 	case SOC_ARCH_EXYNOS7:
10654a6cf76eSKrzysztof Kozlowski 		data->sclk = devm_clk_get(dev, "tmu_sclk");
10666c247393SAbhilash Kesavan 		if (IS_ERR(data->sclk)) {
1067*ca617669SKrzysztof Kozlowski 			ret = dev_err_probe(dev, PTR_ERR(data->sclk), "Failed to get sclk\n");
10686c247393SAbhilash Kesavan 			goto err_clk;
10696c247393SAbhilash Kesavan 		} else {
10706c247393SAbhilash Kesavan 			ret = clk_prepare_enable(data->sclk);
10716c247393SAbhilash Kesavan 			if (ret) {
10724a6cf76eSKrzysztof Kozlowski 				dev_err(dev, "Failed to enable sclk\n");
10736c247393SAbhilash Kesavan 				goto err_clk;
10746c247393SAbhilash Kesavan 			}
10756c247393SAbhilash Kesavan 		}
1076488c7455SChanwoo Choi 		break;
1077488c7455SChanwoo Choi 	default:
1078488c7455SChanwoo Choi 		break;
1079baba1ebbSKrzysztof Kozlowski 	}
10806c247393SAbhilash Kesavan 
1081b72ba67bSMateusz Majewski 	ret = exynos_tmu_initialize(pdev);
1082b72ba67bSMateusz Majewski 	if (ret) {
10834a6cf76eSKrzysztof Kozlowski 		dev_err(dev, "Failed to initialize TMU\n");
1084b72ba67bSMateusz Majewski 		goto err_sclk;
1085b72ba67bSMateusz Majewski 	}
1086b72ba67bSMateusz Majewski 
10874a6cf76eSKrzysztof Kozlowski 	data->tzd = devm_thermal_of_zone_register(dev, 0, data,
10889e4249b4SKrzysztof Kozlowski 						  &exynos_sensor_ops);
10899e4249b4SKrzysztof Kozlowski 	if (IS_ERR(data->tzd)) {
1090*ca617669SKrzysztof Kozlowski 		ret = dev_err_probe(dev, PTR_ERR(data->tzd), "Failed to register sensor\n");
10919e4249b4SKrzysztof Kozlowski 		goto err_sclk;
10929e4249b4SKrzysztof Kozlowski 	}
109359dfa54cSAmit Daniel Kachhap 
1094b72ba67bSMateusz Majewski 	ret = exynos_thermal_zone_configure(pdev);
109559dfa54cSAmit Daniel Kachhap 	if (ret) {
10964a6cf76eSKrzysztof Kozlowski 		dev_err(dev, "Failed to configure the thermal zone\n");
10977ea98f70SDaniel Lezcano 		goto err_sclk;
109859dfa54cSAmit Daniel Kachhap 	}
109959dfa54cSAmit Daniel Kachhap 
11004a6cf76eSKrzysztof Kozlowski 	ret = devm_request_threaded_irq(dev, data->irq, NULL,
110120009a81SMateusz Majewski 					exynos_tmu_threaded_irq,
110220009a81SMateusz Majewski 					IRQF_TRIGGER_RISING
110320009a81SMateusz Majewski 						| IRQF_SHARED | IRQF_ONESHOT,
11044a6cf76eSKrzysztof Kozlowski 					dev_name(dev), data);
1105cebe7373SAmit Daniel Kachhap 	if (ret) {
11064a6cf76eSKrzysztof Kozlowski 		dev_err(dev, "Failed to request irq: %d\n", data->irq);
11077ea98f70SDaniel Lezcano 		goto err_sclk;
1108cebe7373SAmit Daniel Kachhap 	}
110959dfa54cSAmit Daniel Kachhap 
11103b6a1a80SLukasz Majewski 	exynos_tmu_control(pdev, true);
111159dfa54cSAmit Daniel Kachhap 	return 0;
11129e4249b4SKrzysztof Kozlowski 
11136c247393SAbhilash Kesavan err_sclk:
11146c247393SAbhilash Kesavan 	clk_disable_unprepare(data->sclk);
111559dfa54cSAmit Daniel Kachhap err_clk:
111659dfa54cSAmit Daniel Kachhap 	clk_unprepare(data->clk);
111714a11dc7SNaveen Krishna Chatradhi err_clk_sec:
111814a11dc7SNaveen Krishna Chatradhi 	if (!IS_ERR(data->clk_sec))
111914a11dc7SNaveen Krishna Chatradhi 		clk_unprepare(data->clk_sec);
112059dfa54cSAmit Daniel Kachhap 	return ret;
112159dfa54cSAmit Daniel Kachhap }
112259dfa54cSAmit Daniel Kachhap 
exynos_tmu_remove(struct platform_device * pdev)11230b478d7bSUwe Kleine-König static void exynos_tmu_remove(struct platform_device *pdev)
112459dfa54cSAmit Daniel Kachhap {
112559dfa54cSAmit Daniel Kachhap 	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
112659dfa54cSAmit Daniel Kachhap 
11274215688eSBartlomiej Zolnierkiewicz 	exynos_tmu_control(pdev, false);
11284215688eSBartlomiej Zolnierkiewicz 
11296c247393SAbhilash Kesavan 	clk_disable_unprepare(data->sclk);
113059dfa54cSAmit Daniel Kachhap 	clk_unprepare(data->clk);
113114a11dc7SNaveen Krishna Chatradhi 	if (!IS_ERR(data->clk_sec))
113214a11dc7SNaveen Krishna Chatradhi 		clk_unprepare(data->clk_sec);
113359dfa54cSAmit Daniel Kachhap }
113459dfa54cSAmit Daniel Kachhap 
113559dfa54cSAmit Daniel Kachhap #ifdef CONFIG_PM_SLEEP
exynos_tmu_suspend(struct device * dev)113659dfa54cSAmit Daniel Kachhap static int exynos_tmu_suspend(struct device *dev)
113759dfa54cSAmit Daniel Kachhap {
113859dfa54cSAmit Daniel Kachhap 	exynos_tmu_control(to_platform_device(dev), false);
113959dfa54cSAmit Daniel Kachhap 
114059dfa54cSAmit Daniel Kachhap 	return 0;
114159dfa54cSAmit Daniel Kachhap }
114259dfa54cSAmit Daniel Kachhap 
exynos_tmu_resume(struct device * dev)114359dfa54cSAmit Daniel Kachhap static int exynos_tmu_resume(struct device *dev)
114459dfa54cSAmit Daniel Kachhap {
114559dfa54cSAmit Daniel Kachhap 	struct platform_device *pdev = to_platform_device(dev);
114659dfa54cSAmit Daniel Kachhap 
114759dfa54cSAmit Daniel Kachhap 	exynos_tmu_initialize(pdev);
114859dfa54cSAmit Daniel Kachhap 	exynos_tmu_control(pdev, true);
114959dfa54cSAmit Daniel Kachhap 
115059dfa54cSAmit Daniel Kachhap 	return 0;
115159dfa54cSAmit Daniel Kachhap }
115259dfa54cSAmit Daniel Kachhap 
115359dfa54cSAmit Daniel Kachhap static SIMPLE_DEV_PM_OPS(exynos_tmu_pm,
115459dfa54cSAmit Daniel Kachhap 			 exynos_tmu_suspend, exynos_tmu_resume);
115559dfa54cSAmit Daniel Kachhap #define EXYNOS_TMU_PM	(&exynos_tmu_pm)
115659dfa54cSAmit Daniel Kachhap #else
115759dfa54cSAmit Daniel Kachhap #define EXYNOS_TMU_PM	NULL
115859dfa54cSAmit Daniel Kachhap #endif
115959dfa54cSAmit Daniel Kachhap 
116059dfa54cSAmit Daniel Kachhap static struct platform_driver exynos_tmu_driver = {
116159dfa54cSAmit Daniel Kachhap 	.driver = {
116259dfa54cSAmit Daniel Kachhap 		.name   = "exynos-tmu",
116359dfa54cSAmit Daniel Kachhap 		.pm     = EXYNOS_TMU_PM,
116473b5b1d7SSachin Kamat 		.of_match_table = exynos_tmu_match,
116559dfa54cSAmit Daniel Kachhap 	},
116659dfa54cSAmit Daniel Kachhap 	.probe = exynos_tmu_probe,
11670b478d7bSUwe Kleine-König 	.remove_new = exynos_tmu_remove,
116859dfa54cSAmit Daniel Kachhap };
116959dfa54cSAmit Daniel Kachhap 
117059dfa54cSAmit Daniel Kachhap module_platform_driver(exynos_tmu_driver);
117159dfa54cSAmit Daniel Kachhap 
1172ca07ee4eSKrzysztof Kozlowski MODULE_DESCRIPTION("Exynos TMU Driver");
117359dfa54cSAmit Daniel Kachhap MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
117459dfa54cSAmit Daniel Kachhap MODULE_LICENSE("GPL");
117559dfa54cSAmit Daniel Kachhap MODULE_ALIAS("platform:exynos-tmu");
1176