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