* @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;
u8 temp_error1, temp_error2;
struct regulator *regulator;
struct thermal_sensor_conf *reg_conf;
+ int (*tmu_initialize)(struct platform_device *pdev);
};
/*
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))
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;
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;
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,
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,
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,
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,
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,
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,