thermal: exynos: Support thermal tripping
authorAmit Daniel Kachhap <amit.daniel@samsung.com>
Mon, 24 Jun 2013 10:50:32 +0000 (16:20 +0530)
committerEduardo Valentin <eduardo.valentin@ti.com>
Tue, 13 Aug 2013 13:52:01 +0000 (09:52 -0400)
TMU urgently sends active-high signal (thermal trip) to PMU, and thermal
tripping by hardware logic. Thermal tripping means that PMU cuts off the
whole power of SoC by controlling external voltage regulator.

Acked-by: Kukjin Kim <kgene.kim@samsung.com>
Acked-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
Acked-by: Eduardo Valentin <eduardo.valentin@ti.com>
Signed-off-by: Jonghwan Choi <jhbird.choi@samsung.com>
Signed-off-by: Amit Daniel Kachhap <amit.daniel@samsung.com>
Signed-off-by: Eduardo Valentin <eduardo.valentin@ti.com>
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/samsung/exynos_tmu_data.c
drivers/thermal/samsung/exynos_tmu_data.h

index 6fd776f41ebccd0a40710c798dbb03d9fd6eadd7..33f494ea1ed12925d6c4c49860bb93677e8f3d4c 100644 (file)
@@ -117,7 +117,7 @@ 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;
+       unsigned int status, trim_info = 0, con;
        unsigned int rising_threshold = 0, falling_threshold = 0;
        int ret = 0, threshold_code, i, trigger_levs = 0;
 
@@ -144,10 +144,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
                        (data->temp_error2 != 0))
                data->temp_error1 = pdata->efuse_value;
 
-       /* Count trigger levels to be enabled */
-       for (i = 0; i < MAX_THRESHOLD_LEVS; i++)
-               if (pdata->trigger_levels[i])
+       if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) {
+               dev_err(&pdev->dev, "Invalid max trigger level\n");
+               goto out;
+       }
+
+       for (i = 0; i < pdata->max_trigger_level; i++) {
+               if (!pdata->trigger_levels[i])
+                       continue;
+
+               if ((pdata->trigger_type[i] == HW_TRIP) &&
+               (!pdata->trigger_levels[pdata->max_trigger_level - 1])) {
+                       dev_err(&pdev->dev, "Invalid hw trigger level\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               /* Count trigger levels except the HW trip*/
+               if (!(pdata->trigger_type[i] == HW_TRIP))
                        trigger_levs++;
+       }
 
        if (data->soc == SOC_ARCH_EXYNOS4210) {
                /* Write temperature code for threshold */
@@ -165,7 +181,8 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
                writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
        } else if (data->soc == SOC_ARCH_EXYNOS) {
                /* Write temperature code for rising and falling threshold */
-               for (i = 0; i < trigger_levs; i++) {
+               for (i = 0;
+               i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) {
                        threshold_code = temp_to_code(data,
                                                pdata->trigger_levels[i]);
                        if (threshold_code < 0) {
@@ -191,6 +208,24 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
                writel((reg->inten_rise_mask << reg->inten_rise_shift) |
                        (reg->inten_fall_mask << reg->inten_fall_shift),
                                data->base + reg->tmu_intclear);
+
+               /* 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 (threshold_code < 0) {
+                               ret = threshold_code;
+                               goto out;
+                       }
+                       rising_threshold |= threshold_code << 8 * i;
+                       writel(rising_threshold,
+                               data->base + reg->threshold_th0);
+                       con = readl(data->base + reg->tmu_ctrl);
+                       con |= (1 << reg->therm_trip_en_shift);
+                       writel(con, data->base + reg->tmu_ctrl);
+               }
        }
 out:
        clk_disable(data->clk);
index 896aa2ac0bb4dbaad0e200a87833906f595a2193..6cac3931088113fb2574166aad0e2771c72d05cf 100644 (file)
@@ -123,6 +123,7 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
        .trigger_levels[0] = 85,
        .trigger_levels[1] = 103,
        .trigger_levels[2] = 110,
+       .trigger_levels[3] = 120,
        .trigger_enable[0] = true,
        .trigger_enable[1] = true,
        .trigger_enable[2] = true,
@@ -130,6 +131,7 @@ struct exynos_tmu_platform_data const exynos5250_default_tmu_data = {
        .trigger_type[0] = THROTTLE_ACTIVE,
        .trigger_type[1] = THROTTLE_ACTIVE,
        .trigger_type[2] = SW_TRIP,
+       .trigger_type[3] = HW_TRIP,
        .max_trigger_level = 4,
        .gain = 8,
        .reference_voltage = 16,
index 0e2244fb8bd1809f34851e638625846f28b2c05c..4acf070c48176887f92ab2abb682f44993195f81 100644 (file)
@@ -91,6 +91,8 @@
 #define EXYNOS_EMUL_DATA_MASK  0xFF
 #define EXYNOS_EMUL_ENABLE     0x1
 
+#define EXYNOS_MAX_TRIGGER_PER_REG     4
+
 #if defined(CONFIG_CPU_EXYNOS4210)
 extern struct exynos_tmu_platform_data const exynos4210_default_tmu_data;
 #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)