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