brintos

brintos / linux-shallow public Read only

0
0
Text · 33.3 KiB · 96cffb2 Raw
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