thermal: exynos: add ->tmu_initialize method

Add ->tmu_initialize method to struct exynos_tmu_data and
use it in exynos_tmu_initialize().  Then add ->tmu_initialize
implementations for Exynos4210, Exynos4412+ and Exynos5440.
Finally remove no longer needed reg->threshold_th[0,1],
reg->intclr_[fall,rise]_shift and reg->intclr_[rise,fall]_mask
abstractions.

There are more improvements available in the future on top
of this patch like merging HW_TRIP level setting with setting
of other levels for Exynos4412+ or adding separate method
for clearing IRQs using INTCLEAR register (for Exynos5420,
Exynos5260 and Exynos4412+).

There should be no functional changes caused by this patch.

Cc: Amit Daniel Kachhap <amit.daniel@samsung.com>
Cc: Lukasz Majewski <l.majewski@samsung.com>
Cc: Eduardo Valentin <edubezval@gmail.com>
Cc: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Tested-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
This commit is contained in:
Bartlomiej Zolnierkiewicz 2014-11-13 16:01:13 +01:00 committed by Eduardo Valentin
parent fe87789cd4
commit 72d1100b73
3 changed files with 159 additions and 133 deletions

View File

@ -52,6 +52,7 @@
* @temp_error2: fused value of the second point trim.
* @regulator: pointer to the TMU regulator structure.
* @reg_conf: pointer to structure to register with core thermal.
* @tmu_initialize: SoC specific TMU initialization method
*/
struct exynos_tmu_data {
int id;
@ -66,6 +67,7 @@ struct exynos_tmu_data {
u8 temp_error1, temp_error2;
struct regulator *regulator;
struct thermal_sensor_conf *reg_conf;
int (*tmu_initialize)(struct platform_device *pdev);
};
/*
@ -180,118 +182,13 @@ static u32 get_th_reg(struct exynos_tmu_data *data, u32 threshold, bool falling)
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;
const struct exynos_tmu_registers *reg = pdata->registers;
unsigned int status, trim_info = 0, con, ctrl;
unsigned int rising_threshold = 0, falling_threshold = 0;
int ret = 0, threshold_code, i;
int ret;
mutex_lock(&data->lock);
clk_enable(data->clk);
if (!IS_ERR(data->clk_sec))
clk_enable(data->clk_sec);
if (data->soc != SOC_ARCH_EXYNOS5440) {
status = readb(data->base + EXYNOS_TMU_REG_STATUS);
if (!status) {
ret = -EBUSY;
goto out;
}
}
if (data->soc == SOC_ARCH_EXYNOS3250 ||
data->soc == SOC_ARCH_EXYNOS4412 ||
data->soc == SOC_ARCH_EXYNOS5250) {
if (data->soc == SOC_ARCH_EXYNOS3250) {
ctrl = readl(data->base + EXYNOS_TMU_TRIMINFO_CON1);
ctrl |= EXYNOS_TRIMINFO_RELOAD_ENABLE;
writel(ctrl, data->base + EXYNOS_TMU_TRIMINFO_CON1);
}
ctrl = readl(data->base + EXYNOS_TMU_TRIMINFO_CON2);
ctrl |= EXYNOS_TRIMINFO_RELOAD_ENABLE;
writel(ctrl, data->base + EXYNOS_TMU_TRIMINFO_CON2);
}
/* Save trimming info in order to perform calibration */
if (data->soc == SOC_ARCH_EXYNOS5440) {
/*
* For exynos5440 soc triminfo value is swapped between TMU0 and
* TMU2, so the below logic is needed.
*/
switch (data->id) {
case 0:
trim_info = readl(data->base +
EXYNOS5440_EFUSE_SWAP_OFFSET + EXYNOS5440_TMU_S0_7_TRIM);
break;
case 1:
trim_info = readl(data->base + EXYNOS5440_TMU_S0_7_TRIM);
break;
case 2:
trim_info = readl(data->base -
EXYNOS5440_EFUSE_SWAP_OFFSET + EXYNOS5440_TMU_S0_7_TRIM);
}
} else {
/* On exynos5420 the triminfo register is in the shared space */
if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO)
trim_info = readl(data->base_second +
EXYNOS_TMU_REG_TRIMINFO);
else
trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
}
sanitize_temp_error(data, trim_info);
if (data->soc == SOC_ARCH_EXYNOS4210) {
/* Write temperature code for threshold */
threshold_code = temp_to_code(data, pdata->threshold);
writeb(threshold_code,
data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
for (i = 0; i < pdata->non_hw_trigger_levels; i++)
writeb(pdata->trigger_levels[i], data->base +
reg->threshold_th0 + i * sizeof(reg->threshold_th0));
exynos_tmu_clear_irqs(data);
} else {
/* Write temperature code for rising and falling threshold */
rising_threshold = readl(data->base + reg->threshold_th0);
rising_threshold = get_th_reg(data, rising_threshold, false);
if (data->soc != SOC_ARCH_EXYNOS5440)
falling_threshold = get_th_reg(data, 0, true);
writel(rising_threshold,
data->base + reg->threshold_th0);
writel(falling_threshold,
data->base + reg->threshold_th1);
exynos_tmu_clear_irqs(data);
/* if last threshold limit is also present */
i = pdata->max_trigger_level - 1;
if (pdata->trigger_levels[i] &&
(pdata->trigger_type[i] == HW_TRIP)) {
threshold_code = temp_to_code(data,
pdata->trigger_levels[i]);
if (data->soc != SOC_ARCH_EXYNOS5440) {
/* 1-4 level to be assigned in th0 reg */
rising_threshold &= ~(0xff << 8 * i);
rising_threshold |= threshold_code << 8 * i;
writel(rising_threshold,
data->base + EXYNOS_THD_TEMP_RISE);
} else {
/* 5th level to be assigned in th2 reg */
rising_threshold =
threshold_code << EXYNOS5440_TMU_TH_RISE4_SHIFT;
writel(rising_threshold,
data->base + EXYNOS5440_TMU_S0_7_TH2);
}
con = readl(data->base + reg->tmu_ctrl);
con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
writel(con, data->base + reg->tmu_ctrl);
}
}
/*Clear the PMIN in the common TMU register*/
if (data->soc == SOC_ARCH_EXYNOS5440 && !data->id)
writel(0, data->base_second + EXYNOS5440_TMU_PMIN);
out:
ret = data->tmu_initialize(pdev);
clk_disable(data->clk);
mutex_unlock(&data->lock);
if (!IS_ERR(data->clk_sec))
@ -347,6 +244,143 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
mutex_unlock(&data->lock);
}
static int exynos4210_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;
int ret = 0, threshold_code, i;
status = readb(data->base + EXYNOS_TMU_REG_STATUS);
if (!status) {
ret = -EBUSY;
goto out;
}
sanitize_temp_error(data, readl(data->base + EXYNOS_TMU_REG_TRIMINFO));
/* Write temperature code for threshold */
threshold_code = temp_to_code(data, pdata->threshold);
writeb(threshold_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
for (i = 0; i < pdata->non_hw_trigger_levels; i++)
writeb(pdata->trigger_levels[i], data->base +
EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
exynos_tmu_clear_irqs(data);
out:
return ret;
}
static int exynos4412_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, con, ctrl, rising_threshold;
int ret = 0, threshold_code, i;
status = readb(data->base + EXYNOS_TMU_REG_STATUS);
if (!status) {
ret = -EBUSY;
goto out;
}
if (data->soc == SOC_ARCH_EXYNOS3250 ||
data->soc == SOC_ARCH_EXYNOS4412 ||
data->soc == SOC_ARCH_EXYNOS5250) {
if (data->soc == SOC_ARCH_EXYNOS3250) {
ctrl = readl(data->base + EXYNOS_TMU_TRIMINFO_CON1);
ctrl |= EXYNOS_TRIMINFO_RELOAD_ENABLE;
writel(ctrl, data->base + EXYNOS_TMU_TRIMINFO_CON1);
}
ctrl = readl(data->base + EXYNOS_TMU_TRIMINFO_CON2);
ctrl |= EXYNOS_TRIMINFO_RELOAD_ENABLE;
writel(ctrl, data->base + EXYNOS_TMU_TRIMINFO_CON2);
}
/* On exynos5420 the triminfo register is in the shared space */
if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO)
trim_info = readl(data->base_second + EXYNOS_TMU_REG_TRIMINFO);
else
trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
sanitize_temp_error(data, trim_info);
/* Write temperature code for rising and falling threshold */
rising_threshold = readl(data->base + EXYNOS_THD_TEMP_RISE);
rising_threshold = get_th_reg(data, rising_threshold, false);
writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE);
writel(get_th_reg(data, 0, true), data->base + EXYNOS_THD_TEMP_FALL);
exynos_tmu_clear_irqs(data);
/* if last threshold limit is also present */
i = pdata->max_trigger_level - 1;
if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) {
threshold_code = temp_to_code(data, pdata->trigger_levels[i]);
/* 1-4 level to be assigned in th0 reg */
rising_threshold &= ~(0xff << 8 * i);
rising_threshold |= threshold_code << 8 * i;
writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE);
con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
}
out:
return ret;
}
static int exynos5440_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 trim_info = 0, con, rising_threshold;
int ret = 0, threshold_code, i;
/*
* For exynos5440 soc triminfo value is swapped between TMU0 and
* TMU2, so the below logic is needed.
*/
switch (data->id) {
case 0:
trim_info = readl(data->base + EXYNOS5440_EFUSE_SWAP_OFFSET +
EXYNOS5440_TMU_S0_7_TRIM);
break;
case 1:
trim_info = readl(data->base + EXYNOS5440_TMU_S0_7_TRIM);
break;
case 2:
trim_info = readl(data->base - EXYNOS5440_EFUSE_SWAP_OFFSET +
EXYNOS5440_TMU_S0_7_TRIM);
}
sanitize_temp_error(data, trim_info);
/* Write temperature code for rising and falling threshold */
rising_threshold = readl(data->base + EXYNOS5440_TMU_S0_7_TH0);
rising_threshold = get_th_reg(data, rising_threshold, false);
writel(rising_threshold, data->base + EXYNOS5440_TMU_S0_7_TH0);
writel(0, data->base + EXYNOS5440_TMU_S0_7_TH1);
exynos_tmu_clear_irqs(data);
/* if last threshold limit is also present */
i = pdata->max_trigger_level - 1;
if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) {
threshold_code = temp_to_code(data, pdata->trigger_levels[i]);
/* 5th level to be assigned in th2 reg */
rising_threshold =
threshold_code << EXYNOS5440_TMU_TH_RISE4_SHIFT;
writel(rising_threshold, data->base + EXYNOS5440_TMU_S0_7_TH2);
con = readl(data->base + EXYNOS5440_TMU_S0_7_CTRL);
con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL);
}
/* Clear the PMIN in the common TMU register */
if (!data->id)
writel(0, data->base_second + EXYNOS5440_TMU_PMIN);
return ret;
}
static int exynos_tmu_read(struct exynos_tmu_data *data)
{
struct exynos_tmu_platform_data *pdata = data->pdata;
@ -639,16 +673,24 @@ static int exynos_tmu_probe(struct platform_device *pdev)
goto err_clk_sec;
}
if (pdata->type == SOC_ARCH_EXYNOS3250 ||
pdata->type == SOC_ARCH_EXYNOS4210 ||
pdata->type == SOC_ARCH_EXYNOS4412 ||
pdata->type == SOC_ARCH_EXYNOS5250 ||
pdata->type == SOC_ARCH_EXYNOS5260 ||
pdata->type == SOC_ARCH_EXYNOS5420 ||
pdata->type == SOC_ARCH_EXYNOS5420_TRIMINFO ||
pdata->type == SOC_ARCH_EXYNOS5440)
data->soc = pdata->type;
else {
switch (data->soc) {
case SOC_ARCH_EXYNOS4210:
data->tmu_initialize = exynos4210_tmu_initialize;
break;
case SOC_ARCH_EXYNOS3250:
case SOC_ARCH_EXYNOS4412:
case SOC_ARCH_EXYNOS5250:
case SOC_ARCH_EXYNOS5260:
case SOC_ARCH_EXYNOS5420:
case SOC_ARCH_EXYNOS5420_TRIMINFO:
data->tmu_initialize = exynos4412_tmu_initialize;
break;
case SOC_ARCH_EXYNOS5440:
data->tmu_initialize = exynos5440_tmu_initialize;
break;
default:
ret = -EINVAL;
dev_err(&pdev->dev, "Platform not supported\n");
goto err_clk;

View File

@ -73,8 +73,6 @@ enum soc_type {
* slightly across different exynos SOC's.
* @tmu_ctrl: TMU main controller register.
* @tmu_cur_temp: register containing the current temperature of the TMU.
* @threshold_th0: Register containing first set of rising levels.
* @threshold_th1: Register containing second set of rising levels.
* @tmu_inten: register containing the different threshold interrupt
enable bits.
* @inten_rise0_shift: shift bits of rising 0 interrupt bits.
@ -91,9 +89,6 @@ struct exynos_tmu_registers {
u32 tmu_cur_temp;
u32 threshold_th0;
u32 threshold_th1;
u32 tmu_inten;
u32 inten_rise0_shift;
u32 inten_rise1_shift;

View File

@ -28,7 +28,6 @@
static const struct exynos_tmu_registers exynos4210_tmu_registers = {
.tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
.tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
.threshold_th0 = EXYNOS4210_TMU_REG_TRIG_LEVEL0,
.tmu_inten = EXYNOS_TMU_REG_INTEN,
.inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
.inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
@ -83,8 +82,6 @@ struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
static const struct exynos_tmu_registers exynos3250_tmu_registers = {
.tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
.tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
.threshold_th0 = EXYNOS_THD_TEMP_RISE,
.threshold_th1 = EXYNOS_THD_TEMP_FALL,
.tmu_inten = EXYNOS_TMU_REG_INTEN,
.inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
.inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
@ -152,8 +149,6 @@ struct exynos_tmu_init_data const exynos3250_default_tmu_data = {
static const struct exynos_tmu_registers exynos4412_tmu_registers = {
.tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
.tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
.threshold_th0 = EXYNOS_THD_TEMP_RISE,
.threshold_th1 = EXYNOS_THD_TEMP_FALL,
.tmu_inten = EXYNOS_TMU_REG_INTEN,
.inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
.inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
@ -234,8 +229,6 @@ struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
static const struct exynos_tmu_registers exynos5260_tmu_registers = {
.tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
.tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
.threshold_th0 = EXYNOS_THD_TEMP_RISE,
.threshold_th1 = EXYNOS_THD_TEMP_FALL,
.tmu_inten = EXYNOS5260_TMU_REG_INTEN,
.inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
.inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
@ -306,8 +299,6 @@ struct exynos_tmu_init_data const exynos5260_default_tmu_data = {
static const struct exynos_tmu_registers exynos5420_tmu_registers = {
.tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
.tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
.threshold_th0 = EXYNOS_THD_TEMP_RISE,
.threshold_th1 = EXYNOS_THD_TEMP_FALL,
.tmu_inten = EXYNOS_TMU_REG_INTEN,
.inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
.inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
@ -385,8 +376,6 @@ struct exynos_tmu_init_data const exynos5420_default_tmu_data = {
static const struct exynos_tmu_registers exynos5440_tmu_registers = {
.tmu_ctrl = EXYNOS5440_TMU_S0_7_CTRL,
.tmu_cur_temp = EXYNOS5440_TMU_S0_7_TEMP,
.threshold_th0 = EXYNOS5440_TMU_S0_7_TH0,
.threshold_th1 = EXYNOS5440_TMU_S0_7_TH1,
.tmu_inten = EXYNOS5440_TMU_S0_7_IRQEN,
.inten_rise0_shift = EXYNOS5440_TMU_INTEN_RISE0_SHIFT,
.inten_rise1_shift = EXYNOS5440_TMU_INTEN_RISE1_SHIFT,