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: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
This commit is contained in:
parent
dd658e0235
commit
488c7455d7
2 changed files with 186 additions and 2 deletions
|
@ -97,6 +97,32 @@
|
|||
#define EXYNOS4412_MUX_ADDR_VALUE 6
|
||||
#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*/
|
||||
#define EXYNOS5440_TMU_S0_7_TRIM 0x000
|
||||
#define EXYNOS5440_TMU_S0_7_CTRL 0x020
|
||||
|
@ -484,6 +510,101 @@ static int exynos4412_tmu_initialize(struct platform_device *pdev)
|
|||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
emul_con = EXYNOS5260_EMUL_CON;
|
||||
if (data->soc == SOC_ARCH_EXYNOS5433)
|
||||
emul_con = EXYNOS5433_TMU_EMUL_CON;
|
||||
else if (data->soc == SOC_ARCH_EXYNOS7)
|
||||
emul_con = EXYNOS7_TMU_REG_EMUL_CON;
|
||||
else
|
||||
|
@ -882,6 +1047,9 @@ static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data)
|
|||
} else if (data->soc == SOC_ARCH_EXYNOS7) {
|
||||
tmu_intstat = 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 {
|
||||
tmu_intstat = EXYNOS_TMU_REG_INTSTAT;
|
||||
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,exynos5420-tmu", },
|
||||
{ .compatible = "samsung,exynos5420-tmu-ext-triminfo", },
|
||||
{ .compatible = "samsung,exynos5433-tmu", },
|
||||
{ .compatible = "samsung,exynos5440-tmu", },
|
||||
{ .compatible = "samsung,exynos7-tmu", },
|
||||
{ /* sentinel */ },
|
||||
|
@ -949,6 +1118,8 @@ static int exynos_of_get_soc_type(struct device_node *np)
|
|||
else if (of_device_is_compatible(np,
|
||||
"samsung,exynos5420-tmu-ext-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"))
|
||||
return SOC_ARCH_EXYNOS5440;
|
||||
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_clear_irqs = exynos4210_tmu_clear_irqs;
|
||||
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:
|
||||
data->tmu_initialize = exynos5440_tmu_initialize;
|
||||
data->tmu_control = exynos5440_tmu_control;
|
||||
|
@ -1172,7 +1350,9 @@ static int exynos_tmu_probe(struct platform_device *pdev)
|
|||
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");
|
||||
if (IS_ERR(data->sclk)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
ret = exynos_tmu_initialize(pdev);
|
||||
if (ret) {
|
||||
|
|
|
@ -33,6 +33,7 @@ enum soc_type {
|
|||
SOC_ARCH_EXYNOS5260,
|
||||
SOC_ARCH_EXYNOS5420,
|
||||
SOC_ARCH_EXYNOS5420_TRIMINFO,
|
||||
SOC_ARCH_EXYNOS5433,
|
||||
SOC_ARCH_EXYNOS5440,
|
||||
SOC_ARCH_EXYNOS7,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue