diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 6e82fdd860b0..736ef7885878 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -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 { + data->soc = pdata->type; + + 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; diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h index adecc7ff5b8a..f186f4ff44c4 100644 --- a/drivers/thermal/samsung/exynos_tmu.h +++ b/drivers/thermal/samsung/exynos_tmu.h @@ -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; diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c index 1ed8bdc117a0..db3b3bc53f76 100644 --- a/drivers/thermal/samsung/exynos_tmu_data.c +++ b/drivers/thermal/samsung/exynos_tmu_data.c @@ -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,