コード例 #1
0
ファイル: exynos4_tmu.c プロジェクト: gcrisis/m040
static int exynos4210_tmu_initialize(struct platform_device *pdev)
{
	struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
	struct exynos4_tmu_platform_data *pdata = data->pdata;
	unsigned int status, trim_info;
	int ret = 0, threshold_code;

	mutex_lock(&data->lock);
	clk_enable(data->clk);

	status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
	if (!status) {
		ret = -EBUSY;
		goto out;
	}

	/* Save trimming info in order to perform calibration */
	trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
	data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
	data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);

	/* Write temperature code for threshold */
	threshold_code = temp_to_code(data, pdata->threshold);
	if (threshold_code < 0) {
		ret = threshold_code;
		goto out;
	}
	writeb(threshold_code,
		data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);

	writeb(pdata->trigger_levels[0],
		data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
	writeb(pdata->trigger_levels[1],
		data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
	writeb(pdata->trigger_levels[2],
		data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
	writeb(pdata->trigger_levels[3],
		data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);

	writel(EXYNOS4_TMU_INTCLEAR_VAL,
		data->base + EXYNOS4_TMU_REG_INTCLEAR);

out:
	clk_disable(data->clk);
	mutex_unlock(&data->lock);

	return ret;
}
コード例 #2
0
static ssize_t exynos_tmu_emulation_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{
	struct platform_device *pdev = container_of(dev,
					struct platform_device, dev);
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
	unsigned int reg;
	int temp;

	if (data->soc == SOC_ARCH_EXYNOS4210)
		goto out;

	if (!sscanf(buf, "%d\n", &temp) || temp < 0)
		return -EINVAL;

	mutex_lock(&data->lock);
	clk_enable(data->clk);

	reg = readl(data->base + EXYNOS_EMUL_CON);

	if (temp) {
		/* Both CELSIUS and MCELSIUS type are available for input */
		if (temp > MCELSIUS)
			temp /= MCELSIUS;

		reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
			(temp_to_code(data, (temp / MCELSIUS))
			 << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
	} else {
		reg &= ~EXYNOS_EMUL_ENABLE;
	}

	writel(reg, data->base + EXYNOS_EMUL_CON);

	clk_disable(data->clk);
	mutex_unlock(&data->lock);

out:
	return count;
}
コード例 #3
0
static int exynos_tmu_initialize(struct platform_device *pdev, int id)
{
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
	struct exynos_tmu_platform_data *pdata = data->pdata;
	unsigned int status, trim_info, rising_threshold;
	int ret = 0, threshold_code;

	mutex_lock(&data->lock);
	clk_enable(data->clk);

	status = readb(data->base[id] + EXYNOS_TMU_REG_STATUS);
	if (!status) {
		ret = -EBUSY;
		goto out;
	}

	if (data->soc == SOC_ARCH_EXYNOS5) {
		__raw_writel(EXYNOS5_TRIMINFO_RELOAD,
				data->base[id] + EXYNOS5_TMU_TRIMINFO_CON);
	}
	/* Save trimming info in order to perform calibration */
	trim_info = readl(data->base[id] + EXYNOS_TMU_REG_TRIMINFO);
	data->temp_error1[id] = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
	data->temp_error2[id] = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);

	if ((EFUSE_MIN_VALUE > data->temp_error1[id]) ||
			(data->temp_error1[id] > EFUSE_MAX_VALUE) ||
			(data->temp_error2[id] != 0))
		data->temp_error1[id] = pdata->efuse_value;

	if (data->soc == SOC_ARCH_EXYNOS4) {
		/* Write temperature code for threshold */
		threshold_code = temp_to_code(data, pdata->threshold, id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		writeb(threshold_code,
			data->base[id] + EXYNOS4_TMU_REG_THRESHOLD_TEMP);

		writeb(pdata->trigger_levels[0],
			data->base[id] + EXYNOS4_TMU_REG_TRIG_LEVEL0);
		writeb(pdata->trigger_levels[1],
			data->base[id] + EXYNOS4_TMU_REG_TRIG_LEVEL1);
		writeb(pdata->trigger_levels[2],
			data->base[id] + EXYNOS4_TMU_REG_TRIG_LEVEL2);
		writeb(pdata->trigger_levels[3],
			data->base[id] + EXYNOS4_TMU_REG_TRIG_LEVEL3);

		writel(EXYNOS4_TMU_INTCLEAR_VAL,
			data->base[id] + EXYNOS_TMU_REG_INTCLEAR);
	} else if (data->soc == SOC_ARCH_EXYNOS5) {
		/* Write temperature code for threshold */
		threshold_code = temp_to_code(data, pdata->trigger_levels[0], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold = threshold_code;
		threshold_code = temp_to_code(data, pdata->trigger_levels[1], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold |= (threshold_code << 8);
		threshold_code = temp_to_code(data, pdata->trigger_levels[2], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold |= (threshold_code << 16);
		threshold_code = temp_to_code(data, pdata->trigger_levels[3], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold |= (threshold_code << 24);

		writel(rising_threshold,
				data->base[id] + EXYNOS5_THD_TEMP_RISE);
		writel(0, data->base[id] + EXYNOS5_THD_TEMP_FALL);

		writel(EXYNOS5_TMU_CLEAR_RISE_INT|EXYNOS5_TMU_CLEAR_FALL_INT,
				data->base[id] + EXYNOS_TMU_REG_INTCLEAR);
	}
out:
	clk_disable(data->clk);
	mutex_unlock(&data->lock);

	return ret;
}
コード例 #4
0
static int exynos_set_trip_temp(struct thermal_zone_device *thermal, int trip,
				unsigned long temp)
{
	struct exynos_tmu_platform_data *pdata;
	struct exynos_tmu_data *data;
	unsigned int interrupt_en = 0, rising_threshold = 0;
	int threshold_code, i;
	int boost_mode = th_zone->sensor_conf->cooling_data.boost_mode;

	if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
		return -EINVAL;

	if (boost_mode) {
		pr_info("Boost mode now, cannot change trigger level");
		return 0;
	}

	data = th_zone->sensor_conf->private_data;
	pdata = data->pdata;

	clk_enable(data->clk);

	th_zone->sensor_conf->trip_data.trip_val[trip] = temp;

	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		rising_threshold = readl(data->base[i] + EXYNOS5_THD_TEMP_RISE);

		threshold_code = temp_to_code(data, temp, i);

		switch (trip) {
		case 0:
			rising_threshold &= ~0xff;
			rising_threshold |= threshold_code;
			interrupt_en |= pdata->trigger_level0_en;
			break;
		case 1:
			rising_threshold &= ~(0xff << 8);
			rising_threshold |= (threshold_code << 8);
			interrupt_en |= pdata->trigger_level1_en << 4;
			break;
		case 2:
			rising_threshold &= ~(0xff << 16);
			rising_threshold |= (threshold_code << 16);
			interrupt_en |= pdata->trigger_level2_en << 8;
			break;
		default:
			return -EINVAL;
		}

		/* Save same trip info in all tmu sensors */
		writel(rising_threshold, data->base[i] + EXYNOS5_THD_TEMP_RISE);
		writel(interrupt_en, data->base[i] + EXYNOS_TMU_REG_INTEN);
	}

	clk_disable(data->clk);

	printk(KERN_INFO "sysfs : set_trip_temp temp=%d regval=0x%x id=%d\n",
			th_zone->sensor_conf->trip_data.trip_val[trip],
			rising_threshold, trip);

	return 0;
}
コード例 #5
0
static int exynos_tmu_initialize(struct platform_device *pdev, int id)
{
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
	struct exynos_tmu_platform_data *pdata = data->pdata;
	unsigned int status, rising_threshold, falling_threshold;
	int ret = 0, threshold_code;

	mutex_lock(&data->lock);
	clk_enable(data->clk);

	status = readb(data->base[id] + EXYNOS_TMU_REG_STATUS);
	if (!status) {
		ret = -EBUSY;
		goto out;
	}

	if (data->soc == SOC_ARCH_EXYNOS4) {
		/* Write temperature code for threshold */
		threshold_code = temp_to_code(data, pdata->threshold, id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		writeb(threshold_code,
			data->base[id] + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
		writeb(pdata->trigger_levels[0],
			data->base[id] + EXYNOS4_TMU_REG_TRIG_LEVEL0);
		writeb(pdata->trigger_levels[1],
			data->base[id] + EXYNOS4_TMU_REG_TRIG_LEVEL1);
		writeb(pdata->trigger_levels[2],
			data->base[id] + EXYNOS4_TMU_REG_TRIG_LEVEL2);
		writeb(pdata->trigger_levels[3],
			data->base[id] + EXYNOS4_TMU_REG_TRIG_LEVEL3);
		writel(EXYNOS4_TMU_INTCLEAR_VAL,
			data->base[id] + EXYNOS_TMU_REG_INTCLEAR);
	} else if (data->soc == SOC_ARCH_EXYNOS3) {
		/* Write temperature code for threshold */
		threshold_code = temp_to_code(data, pdata->trigger_levels[0], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold = threshold_code;
		falling_threshold = threshold_code - GAP_WITH_RISE;
		threshold_code = temp_to_code(data, pdata->trigger_levels[1], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold |= (threshold_code << THRESH_LEVE1_SHIFT);
		falling_threshold |= ((threshold_code - GAP_WITH_RISE) << THRESH_LEVE1_SHIFT);
		threshold_code = temp_to_code(data, pdata->trigger_levels[2], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold |= (threshold_code << THRESH_LEVE2_SHIFT);
		falling_threshold |= ((threshold_code - GAP_WITH_RISE) << THRESH_LEVE2_SHIFT);
		threshold_code = temp_to_code(data, pdata->trigger_levels[3], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold |= (threshold_code << THRESH_LEVE3_SHIFT);

		writel(rising_threshold, data->base[id] + EXYNOS3_THD_TEMP_RISE);
		writel(falling_threshold, data->base[id] + EXYNOS3_THD_TEMP_FALL);
		writel(EXYNOS3_TMU_CLEAR_RISE_INT|EXYNOS3_TMU_CLEAR_FALL_INT,
				data->base[id] + EXYNOS_TMU_REG_INTCLEAR);
	} else if (data->soc == SOC_ARCH_EXYNOS5) {
		/* Write temperature code for threshold */
		threshold_code = temp_to_code(data, pdata->trigger_levels[0], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold = threshold_code;
		falling_threshold = threshold_code - GAP_WITH_RISE;
		threshold_code = temp_to_code(data, pdata->trigger_levels[1], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold |= (threshold_code << THRESH_LEVE1_SHIFT);
		falling_threshold |= ((threshold_code - GAP_WITH_RISE) << THRESH_LEVE1_SHIFT);
		threshold_code = temp_to_code(data, pdata->trigger_levels[2], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold |= (threshold_code << THRESH_LEVE2_SHIFT);
		falling_threshold |= ((threshold_code - GAP_WITH_RISE) << THRESH_LEVE2_SHIFT);
		threshold_code = temp_to_code(data, pdata->trigger_levels[3], id);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		rising_threshold |= (threshold_code << THRESH_LEVE3_SHIFT);

		writel(rising_threshold, data->base[id] + EXYNOS5_THD_TEMP_RISE);
		writel(falling_threshold, data->base[id] + EXYNOS5_THD_TEMP_FALL);
		writel(EXYNOS5_TMU_CLEAR_RISE_INT|EXYNOS5_TMU_CLEAR_FALL_INT,
				data->base[id] + EXYNOS_TMU_REG_INTCLEAR);
	}
out:
	clk_disable(data->clk);
	mutex_unlock(&data->lock);

	return ret;
}
コード例 #6
0
static int exynos_set_trip_temp(struct thermal_zone_device *thermal, int trip,
				unsigned long temp)
{
	struct exynos_tmu_platform_data *pdata;
	struct exynos_tmu_data *data;
	unsigned int interrupt_en = 0, rising_threshold = 0, falling_threshold;
	int threshold_code, i, con;

	data = th_zone->sensor_conf->private_data;
	pdata = data->pdata;

	clk_enable(data->clk);

	th_zone->sensor_conf->trip_data.trip_val[trip] = temp;

	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		/* TMU core disable  */
		if (i <= GET_TRIP(PANIC_ZONE))
			writel(0, data->base[i] + EXYNOS_TMU_REG_INTEN);

		con = readl(data->base[i] + EXYNOS_TMU_REG_CONTROL);
		con &= ~(0x3);
		con |= EXYNOS_TMU_CORE_OFF;
		writel(con, data->base[i] + EXYNOS_TMU_REG_CONTROL);

		/* Interrupt pending clear  */
		writel(EXYNOS5_TMU_CLEAR_RISE_INT|EXYNOS5_TMU_CLEAR_FALL_INT,
				data->base[i] + EXYNOS_TMU_REG_INTCLEAR);

		/* Change the trigger levels  */
		rising_threshold = readl(data->base[i] + EXYNOS5_THD_TEMP_RISE);
		falling_threshold = readl(data->base[i] + EXYNOS5_THD_TEMP_FALL);
		threshold_code = temp_to_code(data, temp, i);

		switch (trip) {
		case 0:
			rising_threshold &= ~0xff;
			falling_threshold &= ~0xff;
			rising_threshold |= threshold_code;
			falling_threshold |= threshold_code - GAP_WITH_RISE;
			interrupt_en |= pdata->trigger_level0_en;
			interrupt_en |= pdata->trigger_level0_en << FALL_LEVEL0_SHIFT;
			break;
		case 1:
			rising_threshold &= ~(0xff << THRESH_LEVE1_SHIFT);
			falling_threshold &= ~(0xff << THRESH_LEVE1_SHIFT);
			rising_threshold |= (threshold_code << THRESH_LEVE1_SHIFT);
			falling_threshold |= ((threshold_code - GAP_WITH_RISE) << THRESH_LEVE1_SHIFT);
			interrupt_en |= pdata->trigger_level1_en << RISE_LEVEL1_SHIFT;
			interrupt_en |= pdata->trigger_level1_en << FALL_LEVEL1_SHIFT;
			break;
		case 2:
			rising_threshold &= ~(0xff << THRESH_LEVE2_SHIFT);
			falling_threshold &= ~(0xff << THRESH_LEVE2_SHIFT);
			rising_threshold |= (threshold_code << THRESH_LEVE2_SHIFT);
			falling_threshold |= ((threshold_code - GAP_WITH_RISE) << THRESH_LEVE2_SHIFT);
			interrupt_en |= pdata->trigger_level2_en << RISE_LEVEL2_SHIFT;
			interrupt_en |= pdata->trigger_level2_en << FALL_LEVEL2_SHIFT;
			break;
		case 3:
			rising_threshold &= ~(0xff << THRESH_LEVE3_SHIFT);
			rising_threshold |= (threshold_code << THRESH_LEVE3_SHIFT);
			break;
		}

		writel(rising_threshold, data->base[i] + EXYNOS5_THD_TEMP_RISE);
		writel(falling_threshold, data->base[i] + EXYNOS5_THD_TEMP_FALL);

		/* TMU core enable */
		if (i <= GET_TRIP(PANIC_ZONE))
			writel(interrupt_en, data->base[i] + EXYNOS_TMU_REG_INTEN);

		con = readl(data->base[i] + EXYNOS_TMU_REG_CONTROL);
		con &= ~(0x3 | (0x1 << 12));
		con |= (EXYNOS_TMU_CORE_ON | EXYNOS_THERM_TRIP_EN);
		writel(con, data->base[i] + EXYNOS_TMU_REG_CONTROL);
	}

	clk_disable(data->clk);

	printk(KERN_INFO "sysfs : set trip temp[%d] : %d\n", trip,
			th_zone->sensor_conf->trip_data.trip_val[trip]);

	return 0;
}
コード例 #7
0
ファイル: exynos4_tmu.c プロジェクト: gcrisis/m040
static int exynos4x12_tmu_initialize(struct platform_device *pdev)
{
	struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
	struct exynos4_tmu_platform_data *pdata = data->pdata;
	unsigned int trim_info;
	int ret = 0, threshold_code[4], interrupt_code, tmp;

	mutex_lock(&data->lock);
	clk_enable(data->clk);

	tmp = readl(data->base + EXYNOS4X12_TMU_REG_TRIMINFO_CONROL);
	tmp |= EXYNOS4X12_TMU_RELOAD;
	writel(tmp, data->base + EXYNOS4X12_TMU_REG_TRIMINFO_CONROL);

	mdelay(1);

	/* Save trimming info in order to perform calibration */
	trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
	data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;

	/* In case of non e-fusing chip, s/w workaround */
	if (trim_info == 0)
		data->temp_error1 = 0x37;

	pr_debug("%s: triminfo reg = 0x%08x, value = %d\n", __func__,
			trim_info, data->temp_error1);

	/* Write temperature code for threshold */
	threshold_code[0] = temp_to_code(data,
		pdata->threshold + pdata->trigger_levels[0]);
	if (threshold_code[0] < 0) {
		ret = threshold_code[0];
		goto out;
	}
	threshold_code[1] = temp_to_code(data,
		pdata->threshold + pdata->trigger_levels[1]);
	if (threshold_code[1] < 0) {
		ret = threshold_code[1];
		goto out;
	}
	threshold_code[2] = temp_to_code(data,
		pdata->threshold + pdata->trigger_levels[2]);
	if (threshold_code[2] < 0) {
		ret = threshold_code[2];
		goto out;
	}
	threshold_code[3] = temp_to_code(data,
		pdata->threshold + pdata->trigger_levels[3]);
	if (threshold_code[3] < 0) {
		ret = threshold_code[3];
		goto out;
	}

	/* Set interrupt trigger level */
	interrupt_code = ((threshold_code[3] << 24) |
		(threshold_code[2] << 16) | (threshold_code[1] << 8) |
		(threshold_code[0] << 0));
	writel(interrupt_code,
		data->base + EXYNOS4X12_TMU_REG_TRESHOLD_TEMP_RISE);
	mdelay(2);

	writel(EXYNOS4X12_TMU_INTCLEAR_VAL,
		data->base + EXYNOS4_TMU_REG_INTCLEAR);
	
out:
	clk_disable(data->clk);
	mutex_unlock(&data->lock);

	return ret;
}
コード例 #8
0
static int exynos_tmu_initialize(struct platform_device *pdev)
{
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
	struct exynos_tmu_platform_data *pdata = data->pdata;
	unsigned int status, trim_info;
	unsigned int rising_threshold = 0, falling_threshold = 0;
	int ret = 0, threshold_code, i, trigger_levs = 0;

	mutex_lock(&data->lock);
	clk_enable(data->clk);

	status = readb(data->base + EXYNOS_TMU_REG_STATUS);
	if (!status) {
		ret = -EBUSY;
		goto out;
	}

	if (data->soc == SOC_ARCH_EXYNOS) {
		__raw_writel(EXYNOS_TRIMINFO_RELOAD,
				data->base + EXYNOS_TMU_TRIMINFO_CON);
	}
	/* Save trimming info in order to perform calibration */
	trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
	data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
	data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);

	if ((EFUSE_MIN_VALUE > data->temp_error1) ||
			(data->temp_error1 > EFUSE_MAX_VALUE) ||
			(data->temp_error2 != 0))
		data->temp_error1 = pdata->efuse_value;

	/* Count trigger levels to be enabled */
	for (i = 0; i < MAX_THRESHOLD_LEVS; i++)
		if (pdata->trigger_levels[i])
			trigger_levs++;

	if (data->soc == SOC_ARCH_EXYNOS4210) {
		/* Write temperature code for threshold */
		threshold_code = temp_to_code(data, pdata->threshold);
		if (threshold_code < 0) {
			ret = threshold_code;
			goto out;
		}
		writeb(threshold_code,
			data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
		for (i = 0; i < trigger_levs; i++)
			writeb(pdata->trigger_levels[i],
			data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);

		writel(EXYNOS4210_TMU_INTCLEAR_VAL,
			data->base + EXYNOS_TMU_REG_INTCLEAR);
	} else if (data->soc == SOC_ARCH_EXYNOS) {
		/* Write temperature code for rising and falling threshold */
		for (i = 0; i < trigger_levs; i++) {
			threshold_code = temp_to_code(data,
						pdata->trigger_levels[i]);
			if (threshold_code < 0) {
				ret = threshold_code;
				goto out;
			}
			rising_threshold |= threshold_code << 8 * i;
			if (pdata->threshold_falling) {
				threshold_code = temp_to_code(data,
						pdata->trigger_levels[i] -
						pdata->threshold_falling);
				if (threshold_code > 0)
					falling_threshold |=
						threshold_code << 8 * i;
			}
		}

		writel(rising_threshold,
				data->base + EXYNOS_THD_TEMP_RISE);
		writel(falling_threshold,
				data->base + EXYNOS_THD_TEMP_FALL);

		writel(EXYNOS_TMU_CLEAR_RISE_INT | EXYNOS_TMU_CLEAR_FALL_INT,
				data->base + EXYNOS_TMU_REG_INTCLEAR);
	}
out:
	clk_disable(data->clk);
	mutex_unlock(&data->lock);

	return ret;
}
コード例 #9
0
static int exynos_tmu_initialize(struct platform_device *pdev, int id)
{
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
	struct exynos_tmu_platform_data *pdata = data->pdata;
	unsigned int status, trim_info, rising_threshold, falling_threshold;
	int ret = 0, timeout =5, threshold_code;

	mutex_lock(&data->lock);
	clk_enable(data->clk);

	status = readb(data->base[id] + EXYNOS_TMU_REG_STATUS);
	if (!status) {
		ret = -EBUSY;
		goto out;
	}

	__raw_writel(EXYNOS_TRIMINFO_RELOAD1,
			data->base[id] + EXYNOS_TMU_TRIMINFO_CON1);
	__raw_writel(EXYNOS_TRIMINFO_RELOAD2,
			data->base[id] + EXYNOS_TMU_TRIMINFO_CON2);

	while(readl(data->base[id] + EXYNOS_TMU_TRIMINFO_CON2) & EXYNOS_TRIMINFO_RELOAD1) {
		if(!timeout) {
			pr_err("Thermal TRIMINFO register reload failed\n");
			break;
		}
		timeout--;
		cpu_relax();
		usleep_range(5,10);
	}
	/* Save trimming info in order to perform calibration */
	trim_info = readl(data->base[id] + EXYNOS_TMU_REG_TRIMINFO);
	data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
	data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);

	if ((EFUSE_MIN_VALUE > data->temp_error1) ||
			(data->temp_error1 > EFUSE_MAX_VALUE) ||
			(data->temp_error2 != 0))
		data->temp_error1 = pdata->efuse_value;

	/* Write temperature code for threshold */
	threshold_code = temp_to_code(data, pdata->threshold +
			pdata->trigger_levels[0]);
	if (threshold_code < 0) {
		ret = threshold_code;
		goto out;
	}
	rising_threshold = threshold_code;
	falling_threshold = threshold_code - GAP_WITH_RISE;
	threshold_code = temp_to_code(data, pdata->threshold +
			pdata->trigger_levels[1]);
	if (threshold_code < 0) {
		ret = threshold_code;
		goto out;
	}
	rising_threshold |= (threshold_code << THRESH_LEVE1_SHIFT);
	falling_threshold |= ((threshold_code - GAP_WITH_RISE) << THRESH_LEVE1_SHIFT);
	threshold_code = temp_to_code(data, pdata->threshold +
			pdata->trigger_levels[2]);
	if (threshold_code < 0) {
		ret = threshold_code;
		goto out;
	}
	rising_threshold |= (threshold_code << THRESH_LEVE2_SHIFT);
	falling_threshold |= ((threshold_code - GAP_WITH_RISE) << THRESH_LEVE2_SHIFT);
	threshold_code = temp_to_code(data, pdata->threshold +
			pdata->trigger_levels[3]);
	if (threshold_code < 0) {
		ret = threshold_code;
		goto out;
	}
	rising_threshold |= (threshold_code << THRESH_LEVE3_SHIFT);

	writel(rising_threshold,
			data->base[0] + EXYNOS4270_TMU_THRESHOLD_TEMP_RISE);
	writel(falling_threshold, data->base[0] + EXYNOS4270_TMU_THRESHOLD_TEMP_FALL);
	writel(EXYNOS4270_TMU_CLEAR_RISE_INT | EXYNOS4270_TMU_CLEAR_FALL_INT,
			data->base[0] + EXYNOS_TMU_REG_INTCLEAR);

out:
	clk_disable(data->clk);
	mutex_unlock(&data->lock);

	return ret;
}