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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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