thermal: rockchip: add temperature dump when panic
[firefly-linux-kernel-4.4.55.git] / drivers / thermal / rockchip_thermal.c
index 39e2eec57fff236c40a9ed7003dd6ba32407f56a..357d967fc71fa4c679ebaddf49926d543827a062 100644 (file)
@@ -211,18 +211,21 @@ struct rockchip_thermal_data {
 
 #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT       4
 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT     4
-#define TSADCV2_AUTO_PERIOD_TIME               250 /* msec */
-#define TSADCV2_AUTO_PERIOD_HT_TIME            50  /* msec */
+#define TSADCV2_AUTO_PERIOD_TIME               250 /* 250ms */
+#define TSADCV2_AUTO_PERIOD_HT_TIME            50  /* 50ms */
+#define TSADCV3_AUTO_PERIOD_TIME               1875 /* 2.5ms */
+#define TSADCV3_AUTO_PERIOD_HT_TIME            1875 /* 2.5ms */
+
 #define TSADCV2_USER_INTER_PD_SOC              0x340 /* 13 clocks */
 
 #define GRF_SARADC_TESTBIT                     0x0e644
 #define GRF_TSADC_TESTBIT_L                    0x0e648
 #define GRF_TSADC_TESTBIT_H                    0x0e64c
 
-#define GRF_TSADC_TSEN_PD_ON                   (0x30003 << 0)
-#define GRF_TSADC_TSEN_PD_OFF                  (0x30000 << 0)
 #define GRF_SARADC_TESTBIT_ON                  (0x10001 << 2)
 #define GRF_TSADC_TESTBIT_H_ON                 (0x10001 << 2)
+#define GRF_TSADC_VCM_EN_L                     (0x10001 << 7)
+#define GRF_TSADC_VCM_EN_H                     (0x10001 << 7)
 
 /**
  * struct tsadc_table - code to temperature conversion table
@@ -398,13 +401,15 @@ static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table,
                                   int temp)
 {
        int high, low, mid;
+       u32 error = table.data_mask;
 
        low = 0;
        high = table.length - 1;
        mid = (high + low) / 2;
 
+       /* Return mask code data when the temp is over table range */
        if (temp < table.id[low].temp || temp > table.id[high].temp)
-               return 0;
+               goto exit;
 
        while (low <= high) {
                if (temp == table.id[mid].temp)
@@ -416,7 +421,11 @@ static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table,
                mid = (low + high) / 2;
        }
 
-       return 0;
+exit:
+       pr_err("%s: Invalid conversion table: code=%d, temperature=%d\n",
+              __func__, error, temp);
+
+       return error;
 }
 
 static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
@@ -466,7 +475,8 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
                }
                break;
        default:
-               pr_err("Invalid the conversion table\n");
+               pr_err("%s: Invalid the conversion table mode=%d\n",
+                      __func__, table.mode);
        }
 
        /*
@@ -547,14 +557,32 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs,
                /* Set interleave value to workround ic time sync issue */
                writel_relaxed(TSADCV2_USER_INTER_PD_SOC, regs +
                               TSADCV2_USER_CON);
+
+               writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
+               writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT,
+                              regs + TSADCV2_HIGHT_INT_DEBOUNCE);
+               writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME,
+                              regs + TSADCV2_AUTO_PERIOD_HT);
+               writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT,
+                              regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE);
+
        } else {
-               regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_ON);
-               mdelay(10);
-               regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_OFF);
+               /* Enable the voltage common mode feature */
+               regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_VCM_EN_L);
+               regmap_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_VCM_EN_H);
+
                udelay(100); /* The spec note says at least 15 us */
                regmap_write(grf, GRF_SARADC_TESTBIT, GRF_SARADC_TESTBIT_ON);
                regmap_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_TESTBIT_H_ON);
                udelay(200); /* The spec note says at least 90 us */
+
+               writel_relaxed(TSADCV3_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
+               writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT,
+                              regs + TSADCV2_HIGHT_INT_DEBOUNCE);
+               writel_relaxed(TSADCV3_AUTO_PERIOD_HT_TIME,
+                              regs + TSADCV2_AUTO_PERIOD_HT);
+               writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT,
+                              regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE);
        }
 
        if (tshut_polarity == TSHUT_HIGH_ACTIVE)
@@ -563,14 +591,6 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs,
        else
                writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH,
                               regs + TSADCV2_AUTO_CON);
-
-       writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
-       writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT,
-                      regs + TSADCV2_HIGHT_INT_DEBOUNCE);
-       writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME,
-                      regs + TSADCV2_AUTO_PERIOD_HT);
-       writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT,
-                      regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE);
 }
 
 static void rk_tsadcv2_irq_ack(void __iomem *regs)
@@ -637,7 +657,11 @@ static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table,
 {
        u32 alarm_value, int_en;
 
+       /* Make sure the value is valid */
        alarm_value = rk_tsadcv2_temp_to_code(table, temp);
+       if (alarm_value == table.data_mask)
+               return;
+
        writel_relaxed(alarm_value & table.data_mask,
                       regs + TSADCV2_COMP_INT(chn));
 
@@ -651,7 +675,11 @@ static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table,
 {
        u32 tshut_value, val;
 
+       /* Make sure the value is valid */
        tshut_value = rk_tsadcv2_temp_to_code(table, temp);
+       if (tshut_value == table.data_mask)
+               return;
+
        writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn));
 
        /* TSHUT will be valid */
@@ -982,6 +1010,48 @@ static void rockchip_thermal_reset_controller(struct reset_control *reset)
        reset_control_deassert(reset);
 }
 
+static struct platform_device *thermal_device;
+
+void rockchip_dump_temperature(void)
+{
+       struct rockchip_thermal_data *thermal;
+       struct platform_device *pdev;
+       int i;
+
+       if (!thermal_device)
+               return;
+
+       pdev = thermal_device;
+       thermal = platform_get_drvdata(pdev);
+
+       for (i = 0; i < thermal->chip->chn_num; i++) {
+               struct rockchip_thermal_sensor *sensor = &thermal->sensors[i];
+               struct thermal_zone_device *tz = sensor->tzd;
+
+               if (tz->temperature != THERMAL_TEMP_INVALID)
+                       dev_warn(&pdev->dev, "channal %d: temperature(%d C)\n",
+                                i, tz->temperature / 1000);
+       }
+
+       if (thermal->regs) {
+               pr_warn("THERMAL REGS:\n");
+               print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET,
+                              32, 4, thermal->regs, 0x88, false);
+       }
+}
+EXPORT_SYMBOL_GPL(rockchip_dump_temperature);
+
+static int rockchip_thermal_panic(struct notifier_block *this,
+                                 unsigned long ev, void *ptr)
+{
+       rockchip_dump_temperature();
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block rockchip_thermal_panic_block = {
+       .notifier_call = rockchip_thermal_panic,
+};
+
 static int rockchip_thermal_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -1094,6 +1164,11 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, thermal);
 
+       thermal_device = pdev;
+
+       atomic_notifier_chain_register(&panic_notifier_list,
+                                      &rockchip_thermal_panic_block);
+
        return 0;
 
 err_disable_pclk: