[8895] tmu: samsung: Exynos8895 initial bring up
authorSoomin Kim <sm8326.kim@samsung.com>
Mon, 11 Jul 2016 02:20:33 +0000 (11:20 +0900)
committerChungwoo Park <cww.park@samsung.com>
Mon, 21 May 2018 08:09:20 +0000 (17:09 +0900)
Change-Id: I21be6076556a75bfb47864ee5a3a2dabdbcc6d14
Signed-off-by: Soomin Kim <sm8326.kim@samsung.com>
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/samsung/exynos_tmu.h

index 41e12862ac45c7b7851f8666e71c5146b16311ce..de2b782fc9d4e4d2fe39c53827d64e71af6de53b 100644 (file)
@@ -421,6 +421,140 @@ static void exynos8890_tmu_control(struct platform_device *pdev, bool on)
        writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
 }
 
+static int exynos8895_tmu_initialize(struct platform_device *pdev)
+{
+       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+       struct thermal_zone_device *tz = data->tzd;
+       struct exynos_tmu_platform_data *pdata = data->pdata;
+       unsigned int rising_threshold = 0, falling_threshold = 0;
+       int temp, temp_hist;
+       unsigned int trim_info;
+       unsigned int reg_off, bit_off;
+       int threshold_code, i;
+
+       /* Check tmu core ready status */
+       trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
+
+       /* Check thermal calibration type */
+       pdata->cal_type = (trim_info >> EXYNOS_TMU_CALIB_SEL_SHIFT)
+                       & EXYNOS_TMU_CALIB_SEL_MASK;
+
+       /* Check temp_error1 and error2 value */
+       data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK;
+       data->temp_error2 = (trim_info >> EXYNOS_TMU_TRIMINFO_85_P0_SHIFT)
+                               & EXYNOS_TMU_TEMP_MASK;
+
+       if (!data->temp_error1)
+               data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK;
+       if (!data->temp_error2)
+               data->temp_error2 = (pdata->efuse_value >>
+                                       EXYNOS_TMU_TRIMINFO_85_P0_SHIFT)
+                                       & EXYNOS_TMU_TEMP_MASK;
+       /* Write temperature code for rising and falling threshold */
+       for (i = (of_thermal_get_ntrips(tz) - 1); i >= 0; i--) {
+               /*
+                * On exynos7 there are 4 rising and 4 falling threshold
+                * registers (0x50-0x5c and 0x60-0x6c respectively). Each
+                * register holds the value of two threshold levels (at bit
+                * offsets 0 and 16). Based on the fact that there are atmost
+                * eight possible trigger levels, calculate the register and
+                * bit offsets where the threshold levels are to be written.
+                *
+                * e.g. EXYNOS_THD_TEMP_RISE7_6 (0x50)
+                * [24:16] - Threshold level 7
+                * [8:0] - Threshold level 6
+                * e.g. EXYNOS_THD_TEMP_RISE5_4 (0x54)
+                * [24:16] - Threshold level 5
+                * [8:0] - Threshold level 4
+                *
+                * and similarly for falling thresholds.
+                *
+                * Based on the above, calculate the register and bit offsets
+                * for rising/falling threshold levels and populate them.
+                */
+               reg_off = ((7 - i) / 2) * 4;
+               bit_off = ((8 - i) % 2);
+
+               tz->ops->get_trip_temp(tz, i, &temp);
+               temp /= MCELSIUS;
+
+               tz->ops->get_trip_hyst(tz, i, &temp_hist);
+               temp_hist = temp - (temp_hist / MCELSIUS);
+
+               /* Set 9-bit temperature code for rising threshold levels */
+               threshold_code = temp_to_code(data, temp);
+               rising_threshold = readl(data->base +
+                       EXYNOS_THD_TEMP_RISE7_6 + reg_off);
+               rising_threshold &= ~(EXYNOS_TMU_TEMP_MASK << (16 * bit_off));
+               rising_threshold |= threshold_code << (16 * bit_off);
+               writel(rising_threshold,
+                      data->base + EXYNOS_THD_TEMP_RISE7_6 + reg_off);
+
+               /* Set 9-bit temperature code for falling threshold levels */
+               threshold_code = temp_to_code(data, temp_hist);
+               falling_threshold &= ~(EXYNOS_TMU_TEMP_MASK << (16 * bit_off));
+               falling_threshold |= threshold_code << (16 * bit_off);
+               writel(falling_threshold,
+                      data->base + EXYNOS_THD_TEMP_FALL7_6 + reg_off);
+       }
+
+       data->tmu_clear_irqs(data);
+
+       return 0;
+}
+
+static void exynos8895_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, trim_info, trim_info1;
+       unsigned int t_buf_vref_sel, t_buf_slope_sel;
+
+       trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
+       trim_info1 = readl(data->base + EXYNOS_TMU_REG_TRIMINFO1);
+
+       /* Save fuse buf_vref_sel, calib_sel value to TRIMINFO and 1 register */
+       t_buf_vref_sel = (trim_info >> EXYNOS_TMU_T_BUF_VREF_SEL_SHIFT)
+                               & (EXYNOS_TMU_T_BUF_VREF_SEL_MASK);
+       t_buf_slope_sel = (trim_info1 >> EXYNOS_TMU_T_BUF_SLOPE_SEL_SHIFT)
+                               & (EXYNOS_TMU_T_BUF_SLOPE_SEL_MASK);
+
+       con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));
+
+       if (on) {
+               con |= (t_buf_vref_sel << EXYNOS_TMU_REF_VOLTAGE_SHIFT);
+               con |= (t_buf_slope_sel << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT);
+               con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
+               con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
+               interrupt_en =
+                       (of_thermal_is_trip_valid(tz, 7)
+                       << EXYNOS_TMU_INTEN_RISE7_SHIFT) |
+                       (of_thermal_is_trip_valid(tz, 6)
+                       << EXYNOS_TMU_INTEN_RISE6_SHIFT) |
+                       (of_thermal_is_trip_valid(tz, 5)
+                       << EXYNOS_TMU_INTEN_RISE5_SHIFT) |
+                       (of_thermal_is_trip_valid(tz, 4)
+                       << EXYNOS_TMU_INTEN_RISE4_SHIFT) |
+                       (of_thermal_is_trip_valid(tz, 3)
+                       << EXYNOS_TMU_INTEN_RISE3_SHIFT) |
+                       (of_thermal_is_trip_valid(tz, 2)
+                       << EXYNOS_TMU_INTEN_RISE2_SHIFT) |
+                       (of_thermal_is_trip_valid(tz, 1)
+                       << EXYNOS_TMU_INTEN_RISE1_SHIFT) |
+                       (of_thermal_is_trip_valid(tz, 0)
+                       << EXYNOS_TMU_INTEN_RISE0_SHIFT);
+
+               interrupt_en |=
+                       interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
+       } else {
+               con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
+               con &= ~(1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
+               interrupt_en = 0; /* Disable all interrupts */
+       }
+
+       writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
+       writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
+}
 static int exynos_get_temp(void *p, int *temp)
 {
        struct exynos_tmu_data *data = p;
@@ -526,6 +660,12 @@ static int exynos8890_tmu_read(struct exynos_tmu_data *data)
                EXYNOS_TMU_TEMP_MASK;
 }
 
+static int exynos8895_tmu_read(struct exynos_tmu_data *data)
+{
+       return readw(data->base + EXYNOS_TMU_REG_CURRENT_TEMP) &
+               EXYNOS_TMU_TEMP_MASK;
+}
+
 static void exynos_tmu_work(struct work_struct *work)
 {
        struct exynos_tmu_data *data = container_of(work,
@@ -550,6 +690,15 @@ static void exynos8890_tmu_clear_irqs(struct exynos_tmu_data *data)
        writel(val_irq, data->base + EXYNOS_TMU_REG_INTPEND);
 }
 
+static void exynos8895_tmu_clear_irqs(struct exynos_tmu_data *data)
+{
+       unsigned int val_irq;
+
+
+       val_irq = readl(data->base + EXYNOS_TMU_REG_INTPEND);
+       writel(val_irq, data->base + EXYNOS_TMU_REG_INTPEND);
+}
+
 static irqreturn_t exynos_tmu_irq(int irq, void *id)
 {
        struct exynos_tmu_data *data = id;
@@ -594,6 +743,7 @@ static struct notifier_block exynos_tmu_pm_notifier = {
 
 static const struct of_device_id exynos_tmu_match[] = {
        { .compatible = "samsung,exynos8890-tmu", },
+       { .compatible = "samsung,exynos8895-tmu", },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, exynos_tmu_match);
@@ -602,6 +752,8 @@ static int exynos_of_get_soc_type(struct device_node *np)
 {
        if (of_device_is_compatible(np, "samsung,exynos8890-tmu"))
                return SOC_ARCH_EXYNOS8890;
+       if (of_device_is_compatible(np, "samsung,exynos8895-tmu"))
+               return SOC_ARCH_EXYNOS8895;
 
        return -EINVAL;
 }
@@ -700,6 +852,14 @@ static int exynos_map_dt_data(struct platform_device *pdev)
                data->tmu_set_emulation = exynos8890_tmu_set_emulation;
                data->tmu_clear_irqs = exynos8890_tmu_clear_irqs;
                break;
+       case SOC_ARCH_EXYNOS8895:
+               data->tmu_initialize = exynos8895_tmu_initialize;
+               data->tmu_control = exynos8895_tmu_control;
+               data->tmu_read = exynos8895_tmu_read;
+               data->tmu_set_emulation = exynos8890_tmu_set_emulation;
+               data->tmu_clear_irqs = exynos8895_tmu_clear_irqs;
+               break;
+
        default:
                dev_err(&pdev->dev, "Platform not supported\n");
                return -EINVAL;
index c412b4e133b424c2cf8aee3a3dcc49a53fa1fa4b..31d6ec0a6be0c489ca6979fda617d2adb146358c 100644 (file)
@@ -27,6 +27,7 @@
 
 enum soc_type {
        SOC_ARCH_EXYNOS8890 = 1,
+       SOC_ARCH_EXYNOS8895 = 2,
 };
 
 /**