Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 488c7455 authored by Chanwoo Choi's avatar Chanwoo Choi Committed by Eduardo Valentin
Browse files

thermal: exynos: Add the support for Exynos5433 TMU



This patch adds the support for Exynos5433's TMU (Thermal Management Unit).
Exynos5433 has a little different register bit fields as following description:
- Support the eight trip points for rising/falling interrupt by using two registers
- Read the calibration type (1-point or 2-point) and sensor id from TRIMINFO register
- Use a little different register address

Cc: Zhang Rui <rui.zhang@intel.com>
Cc: Eduardo Valentin <edubezval@gmail.com>
Cc: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: default avatarChanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: default avatarEduardo Valentin <edubezval@gmail.com>
parent dd658e02
Loading
Loading
Loading
Loading
+185 −2
Original line number Original line Diff line number Diff line
@@ -97,6 +97,32 @@
#define EXYNOS4412_MUX_ADDR_VALUE          6
#define EXYNOS4412_MUX_ADDR_VALUE          6
#define EXYNOS4412_MUX_ADDR_SHIFT          20
#define EXYNOS4412_MUX_ADDR_SHIFT          20


/* Exynos5433 specific registers */
#define EXYNOS5433_TMU_REG_CONTROL1		0x024
#define EXYNOS5433_TMU_SAMPLING_INTERVAL	0x02c
#define EXYNOS5433_TMU_COUNTER_VALUE0		0x030
#define EXYNOS5433_TMU_COUNTER_VALUE1		0x034
#define EXYNOS5433_TMU_REG_CURRENT_TEMP1	0x044
#define EXYNOS5433_THD_TEMP_RISE3_0		0x050
#define EXYNOS5433_THD_TEMP_RISE7_4		0x054
#define EXYNOS5433_THD_TEMP_FALL3_0		0x060
#define EXYNOS5433_THD_TEMP_FALL7_4		0x064
#define EXYNOS5433_TMU_REG_INTEN		0x0c0
#define EXYNOS5433_TMU_REG_INTPEND		0x0c8
#define EXYNOS5433_TMU_EMUL_CON			0x110
#define EXYNOS5433_TMU_PD_DET_EN		0x130

#define EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT	16
#define EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT	23
#define EXYNOS5433_TRIMINFO_SENSOR_ID_MASK	\
			(0xf << EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT)
#define EXYNOS5433_TRIMINFO_CALIB_SEL_MASK	BIT(23)

#define EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING	0
#define EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING	1

#define EXYNOS5433_PD_DET_EN			1

/*exynos5440 specific registers*/
/*exynos5440 specific registers*/
#define EXYNOS5440_TMU_S0_7_TRIM		0x000
#define EXYNOS5440_TMU_S0_7_TRIM		0x000
#define EXYNOS5440_TMU_S0_7_CTRL		0x020
#define EXYNOS5440_TMU_S0_7_CTRL		0x020
@@ -484,6 +510,101 @@ static int exynos4412_tmu_initialize(struct platform_device *pdev)
	return ret;
	return ret;
}
}


static int exynos5433_tmu_initialize(struct platform_device *pdev)
{
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
	struct exynos_tmu_platform_data *pdata = data->pdata;
	struct thermal_zone_device *tz = data->tzd;
	unsigned int status, trim_info;
	unsigned int rising_threshold = 0, falling_threshold = 0;
	unsigned long temp, temp_hist;
	int ret = 0, threshold_code, i, sensor_id, cal_type;

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

	trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
	sanitize_temp_error(data, trim_info);

	/* Read the temperature sensor id */
	sensor_id = (trim_info & EXYNOS5433_TRIMINFO_SENSOR_ID_MASK)
				>> EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT;
	dev_info(&pdev->dev, "Temperature sensor ID: 0x%x\n", sensor_id);

	/* Read the calibration mode */
	writel(trim_info, data->base + EXYNOS_TMU_REG_TRIMINFO);
	cal_type = (trim_info & EXYNOS5433_TRIMINFO_CALIB_SEL_MASK)
				>> EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT;

	switch (cal_type) {
	case EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING:
		pdata->cal_type = TYPE_ONE_POINT_TRIMMING;
		break;
	case EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING:
		pdata->cal_type = TYPE_TWO_POINT_TRIMMING;
		break;
	default:
		pdata->cal_type = TYPE_ONE_POINT_TRIMMING;
		break;
	};

	dev_info(&pdev->dev, "Calibration type is %d-point calibration\n",
			cal_type ?  2 : 1);

	/* Write temperature code for rising and falling threshold */
	for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
		int rising_reg_offset, falling_reg_offset;
		int j = 0;

		switch (i) {
		case 0:
		case 1:
		case 2:
		case 3:
			rising_reg_offset = EXYNOS5433_THD_TEMP_RISE3_0;
			falling_reg_offset = EXYNOS5433_THD_TEMP_FALL3_0;
			j = i;
			break;
		case 4:
		case 5:
		case 6:
		case 7:
			rising_reg_offset = EXYNOS5433_THD_TEMP_RISE7_4;
			falling_reg_offset = EXYNOS5433_THD_TEMP_FALL7_4;
			j = i - 4;
			break;
		default:
			continue;
		}

		/* Write temperature code for rising threshold */
		tz->ops->get_trip_temp(tz, i, &temp);
		temp /= MCELSIUS;
		threshold_code = temp_to_code(data, temp);

		rising_threshold = readl(data->base + rising_reg_offset);
		rising_threshold |= (threshold_code << j * 8);
		writel(rising_threshold, data->base + rising_reg_offset);

		/* Write temperature code for falling threshold */
		tz->ops->get_trip_hyst(tz, i, &temp_hist);
		temp_hist = temp - (temp_hist / MCELSIUS);
		threshold_code = temp_to_code(data, temp_hist);

		falling_threshold = readl(data->base + falling_reg_offset);
		falling_threshold &= ~(0xff << j * 8);
		falling_threshold |= (threshold_code << j * 8);
		writel(falling_threshold, data->base + falling_reg_offset);
	}

	data->tmu_clear_irqs(data);
out:
	return ret;
}

static int exynos5440_tmu_initialize(struct platform_device *pdev)
static int exynos5440_tmu_initialize(struct platform_device *pdev)
{
{
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
@@ -643,6 +764,48 @@ static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
}
}


static void exynos5433_tmu_control(struct platform_device *pdev, bool on)
{
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
	struct thermal_zone_device *tz = data->tzd;
	unsigned int con, interrupt_en, pd_det_en;

	con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));

	if (on) {
		con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
		interrupt_en =
			(of_thermal_is_trip_valid(tz, 7)
			<< EXYNOS7_TMU_INTEN_RISE7_SHIFT) |
			(of_thermal_is_trip_valid(tz, 6)
			<< EXYNOS7_TMU_INTEN_RISE6_SHIFT) |
			(of_thermal_is_trip_valid(tz, 5)
			<< EXYNOS7_TMU_INTEN_RISE5_SHIFT) |
			(of_thermal_is_trip_valid(tz, 4)
			<< EXYNOS7_TMU_INTEN_RISE4_SHIFT) |
			(of_thermal_is_trip_valid(tz, 3)
			<< EXYNOS7_TMU_INTEN_RISE3_SHIFT) |
			(of_thermal_is_trip_valid(tz, 2)
			<< EXYNOS7_TMU_INTEN_RISE2_SHIFT) |
			(of_thermal_is_trip_valid(tz, 1)
			<< EXYNOS7_TMU_INTEN_RISE1_SHIFT) |
			(of_thermal_is_trip_valid(tz, 0)
			<< EXYNOS7_TMU_INTEN_RISE0_SHIFT);

		interrupt_en |=
			interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
	} else {
		con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
		interrupt_en = 0; /* Disable all interrupts */
	}

	pd_det_en = on ? EXYNOS5433_PD_DET_EN : 0;

	writel(pd_det_en, data->base + EXYNOS5433_TMU_PD_DET_EN);
	writel(interrupt_en, data->base + EXYNOS5433_TMU_REG_INTEN);
	writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
}

static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
{
{
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
	struct exynos_tmu_data *data = platform_get_drvdata(pdev);
@@ -770,6 +933,8 @@ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data,


	if (data->soc == SOC_ARCH_EXYNOS5260)
	if (data->soc == SOC_ARCH_EXYNOS5260)
		emul_con = EXYNOS5260_EMUL_CON;
		emul_con = EXYNOS5260_EMUL_CON;
	if (data->soc == SOC_ARCH_EXYNOS5433)
		emul_con = EXYNOS5433_TMU_EMUL_CON;
	else if (data->soc == SOC_ARCH_EXYNOS7)
	else if (data->soc == SOC_ARCH_EXYNOS7)
		emul_con = EXYNOS7_TMU_REG_EMUL_CON;
		emul_con = EXYNOS7_TMU_REG_EMUL_CON;
	else
	else
@@ -882,6 +1047,9 @@ static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data)
	} else if (data->soc == SOC_ARCH_EXYNOS7) {
	} else if (data->soc == SOC_ARCH_EXYNOS7) {
		tmu_intstat = EXYNOS7_TMU_REG_INTPEND;
		tmu_intstat = EXYNOS7_TMU_REG_INTPEND;
		tmu_intclear = EXYNOS7_TMU_REG_INTPEND;
		tmu_intclear = EXYNOS7_TMU_REG_INTPEND;
	} else if (data->soc == SOC_ARCH_EXYNOS5433) {
		tmu_intstat = EXYNOS5433_TMU_REG_INTPEND;
		tmu_intclear = EXYNOS5433_TMU_REG_INTPEND;
	} else {
	} else {
		tmu_intstat = EXYNOS_TMU_REG_INTSTAT;
		tmu_intstat = EXYNOS_TMU_REG_INTSTAT;
		tmu_intclear = EXYNOS_TMU_REG_INTCLEAR;
		tmu_intclear = EXYNOS_TMU_REG_INTCLEAR;
@@ -926,6 +1094,7 @@ static const struct of_device_id exynos_tmu_match[] = {
	{ .compatible = "samsung,exynos5260-tmu", },
	{ .compatible = "samsung,exynos5260-tmu", },
	{ .compatible = "samsung,exynos5420-tmu", },
	{ .compatible = "samsung,exynos5420-tmu", },
	{ .compatible = "samsung,exynos5420-tmu-ext-triminfo", },
	{ .compatible = "samsung,exynos5420-tmu-ext-triminfo", },
	{ .compatible = "samsung,exynos5433-tmu", },
	{ .compatible = "samsung,exynos5440-tmu", },
	{ .compatible = "samsung,exynos5440-tmu", },
	{ .compatible = "samsung,exynos7-tmu", },
	{ .compatible = "samsung,exynos7-tmu", },
	{ /* sentinel */ },
	{ /* sentinel */ },
@@ -949,6 +1118,8 @@ static int exynos_of_get_soc_type(struct device_node *np)
	else if (of_device_is_compatible(np,
	else if (of_device_is_compatible(np,
					 "samsung,exynos5420-tmu-ext-triminfo"))
					 "samsung,exynos5420-tmu-ext-triminfo"))
		return SOC_ARCH_EXYNOS5420_TRIMINFO;
		return SOC_ARCH_EXYNOS5420_TRIMINFO;
	else if (of_device_is_compatible(np, "samsung,exynos5433-tmu"))
		return SOC_ARCH_EXYNOS5433;
	else if (of_device_is_compatible(np, "samsung,exynos5440-tmu"))
	else if (of_device_is_compatible(np, "samsung,exynos5440-tmu"))
		return SOC_ARCH_EXYNOS5440;
		return SOC_ARCH_EXYNOS5440;
	else if (of_device_is_compatible(np, "samsung,exynos7-tmu"))
	else if (of_device_is_compatible(np, "samsung,exynos7-tmu"))
@@ -1069,6 +1240,13 @@ static int exynos_map_dt_data(struct platform_device *pdev)
		data->tmu_set_emulation = exynos4412_tmu_set_emulation;
		data->tmu_set_emulation = exynos4412_tmu_set_emulation;
		data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
		data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
		break;
		break;
	case SOC_ARCH_EXYNOS5433:
		data->tmu_initialize = exynos5433_tmu_initialize;
		data->tmu_control = exynos5433_tmu_control;
		data->tmu_read = exynos4412_tmu_read;
		data->tmu_set_emulation = exynos4412_tmu_set_emulation;
		data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
		break;
	case SOC_ARCH_EXYNOS5440:
	case SOC_ARCH_EXYNOS5440:
		data->tmu_initialize = exynos5440_tmu_initialize;
		data->tmu_initialize = exynos5440_tmu_initialize;
		data->tmu_control = exynos5440_tmu_control;
		data->tmu_control = exynos5440_tmu_control;
@@ -1172,7 +1350,9 @@ static int exynos_tmu_probe(struct platform_device *pdev)
		goto err_clk_sec;
		goto err_clk_sec;
	}
	}


	if (data->soc == SOC_ARCH_EXYNOS7) {
	switch (data->soc) {
	case SOC_ARCH_EXYNOS5433:
	case SOC_ARCH_EXYNOS7:
		data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk");
		data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk");
		if (IS_ERR(data->sclk)) {
		if (IS_ERR(data->sclk)) {
			dev_err(&pdev->dev, "Failed to get sclk\n");
			dev_err(&pdev->dev, "Failed to get sclk\n");
@@ -1184,7 +1364,10 @@ static int exynos_tmu_probe(struct platform_device *pdev)
				goto err_clk;
				goto err_clk;
			}
			}
		}
		}
	}
		break;
	default:
		break;
	};


	ret = exynos_tmu_initialize(pdev);
	ret = exynos_tmu_initialize(pdev);
	if (ret) {
	if (ret) {
+1 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@ enum soc_type {
	SOC_ARCH_EXYNOS5260,
	SOC_ARCH_EXYNOS5260,
	SOC_ARCH_EXYNOS5420,
	SOC_ARCH_EXYNOS5420,
	SOC_ARCH_EXYNOS5420_TRIMINFO,
	SOC_ARCH_EXYNOS5420_TRIMINFO,
	SOC_ARCH_EXYNOS5433,
	SOC_ARCH_EXYNOS5440,
	SOC_ARCH_EXYNOS5440,
	SOC_ARCH_EXYNOS7,
	SOC_ARCH_EXYNOS7,
};
};