]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/thermal/rockchip_thermal.c
Merge tag 'platform-drivers-x86-v4.10-4' of git://git.infradead.org/linux-platform...
[mirror_ubuntu-artful-kernel.git] / drivers / thermal / rockchip_thermal.c
index b811b0fb61b1381fba45440f963030aba9ee509a..4c779651245351ea488cf20dec87199d755eb135 100644 (file)
@@ -118,12 +118,12 @@ struct rockchip_tsadc_chip {
        void (*control)(void __iomem *reg, bool on);
 
        /* Per-sensor methods */
-       int (*get_temp)(struct chip_tsadc_table table,
+       int (*get_temp)(const struct chip_tsadc_table *table,
                        int chn, void __iomem *reg, int *temp);
-       void (*set_alarm_temp)(struct chip_tsadc_table table,
-                              int chn, void __iomem *reg, int temp);
-       void (*set_tshut_temp)(struct chip_tsadc_table table,
-                              int chn, void __iomem *reg, int temp);
+       int (*set_alarm_temp)(const struct chip_tsadc_table *table,
+                             int chn, void __iomem *reg, int temp);
+       int (*set_tshut_temp)(const struct chip_tsadc_table *table,
+                             int chn, void __iomem *reg, int temp);
        void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
 
        /* Per-table methods */
@@ -317,6 +317,7 @@ static const struct tsadc_table rk3288_code_table[] = {
        {3452, 115000},
        {3437, 120000},
        {3421, 125000},
+       {0, 125000},
 };
 
 static const struct tsadc_table rk3368_code_table[] = {
@@ -397,59 +398,80 @@ static const struct tsadc_table rk3399_code_table[] = {
        {TSADCV3_DATA_MASK, 125000},
 };
 
-static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table,
+static u32 rk_tsadcv2_temp_to_code(const struct chip_tsadc_table *table,
                                   int temp)
 {
        int high, low, mid;
-       u32 error = 0;
+       unsigned long num;
+       unsigned int denom;
+       u32 error = table->data_mask;
 
        low = 0;
-       high = table.length - 1;
+       high = (table->length - 1) - 1; /* ignore the last check for table */
        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) {
-               error = table.data_mask;
+       if (temp < table->id[low].temp || temp > table->id[high].temp)
                goto exit;
-       }
 
        while (low <= high) {
-               if (temp == table.id[mid].temp)
-                       return table.id[mid].code;
-               else if (temp < table.id[mid].temp)
+               if (temp == table->id[mid].temp)
+                       return table->id[mid].code;
+               else if (temp < table->id[mid].temp)
                        high = mid - 1;
                else
                        low = mid + 1;
                mid = (low + high) / 2;
        }
 
+       /*
+        * The conversion code granularity provided by the table. Let's
+        * assume that the relationship between temperature and
+        * analog value between 2 table entries is linear and interpolate
+        * to produce less granular result.
+        */
+       num = abs(table->id[mid + 1].code - table->id[mid].code);
+       num *= temp - table->id[mid].temp;
+       denom = table->id[mid + 1].temp - table->id[mid].temp;
+
+       switch (table->mode) {
+       case ADC_DECREMENT:
+               return table->id[mid].code - (num / denom);
+       case ADC_INCREMENT:
+               return table->id[mid].code + (num / denom);
+       default:
+               pr_err("%s: unknown table mode: %d\n", __func__, table->mode);
+               return error;
+       }
+
 exit:
-       pr_err("Invalid the conversion, error=%d\n", error);
+       pr_err("%s: invalid temperature, temp=%d error=%d\n",
+              __func__, temp, error);
        return error;
 }
 
-static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
-                                  int *temp)
+static int rk_tsadcv2_code_to_temp(const struct chip_tsadc_table *table,
+                                  u32 code, int *temp)
 {
        unsigned int low = 1;
-       unsigned int high = table.length - 1;
+       unsigned int high = table->length - 1;
        unsigned int mid = (low + high) / 2;
        unsigned int num;
        unsigned long denom;
 
-       WARN_ON(table.length < 2);
+       WARN_ON(table->length < 2);
 
-       switch (table.mode) {
+       switch (table->mode) {
        case ADC_DECREMENT:
-               code &= table.data_mask;
-               if (code < table.id[high].code)
+               code &= table->data_mask;
+               if (code <= table->id[high].code)
                        return -EAGAIN;         /* Incorrect reading */
 
                while (low <= high) {
-                       if (code >= table.id[mid].code &&
-                           code < table.id[mid - 1].code)
+                       if (code >= table->id[mid].code &&
+                           code < table->id[mid - 1].code)
                                break;
-                       else if (code < table.id[mid].code)
+                       else if (code < table->id[mid].code)
                                low = mid + 1;
                        else
                                high = mid - 1;
@@ -458,15 +480,15 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
                }
                break;
        case ADC_INCREMENT:
-               code &= table.data_mask;
-               if (code < table.id[low].code)
+               code &= table->data_mask;
+               if (code < table->id[low].code)
                        return -EAGAIN;         /* Incorrect reading */
 
                while (low <= high) {
-                       if (code <= table.id[mid].code &&
-                           code > table.id[mid - 1].code)
+                       if (code <= table->id[mid].code &&
+                           code > table->id[mid - 1].code)
                                break;
-                       else if (code > table.id[mid].code)
+                       else if (code > table->id[mid].code)
                                low = mid + 1;
                        else
                                high = mid - 1;
@@ -475,7 +497,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: unknown table mode: %d\n", __func__, table->mode);
+               return -EINVAL;
        }
 
        /*
@@ -484,10 +507,10 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
         * temperature between 2 table entries is linear and interpolate
         * to produce less granular result.
         */
-       num = table.id[mid].temp - table.id[mid - 1].temp;
-       num *= abs(table.id[mid - 1].code - code);
-       denom = abs(table.id[mid - 1].code - table.id[mid].code);
-       *temp = table.id[mid - 1].temp + (num / denom);
+       num = table->id[mid].temp - table->id[mid - 1].temp;
+       num *= abs(table->id[mid - 1].code - code);
+       denom = abs(table->id[mid - 1].code - table->id[mid].code);
+       *temp = table->id[mid - 1].temp + (num / denom);
 
        return 0;
 }
@@ -638,7 +661,7 @@ static void rk_tsadcv3_control(void __iomem *regs, bool enable)
        writel_relaxed(val, regs + TSADCV2_AUTO_CON);
 }
 
-static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
+static int rk_tsadcv2_get_temp(const struct chip_tsadc_table *table,
                               int chn, void __iomem *regs, int *temp)
 {
        u32 val;
@@ -648,39 +671,57 @@ static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
        return rk_tsadcv2_code_to_temp(table, val, temp);
 }
 
-static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table,
-                                 int chn, void __iomem *regs, int temp)
+static int rk_tsadcv2_alarm_temp(const struct chip_tsadc_table *table,
+                                int chn, void __iomem *regs, int temp)
 {
-       u32 alarm_value, int_en;
+       u32 alarm_value;
+       u32 int_en, int_clr;
+
+       /*
+        * In some cases, some sensors didn't need the trip points, the
+        * set_trips will pass {-INT_MAX, INT_MAX} to trigger tsadc alarm
+        * in the end, ignore this case and disable the high temperature
+        * interrupt.
+        */
+       if (temp == INT_MAX) {
+               int_clr = readl_relaxed(regs + TSADCV2_INT_EN);
+               int_clr &= ~TSADCV2_INT_SRC_EN(chn);
+               writel_relaxed(int_clr, regs + TSADCV2_INT_EN);
+               return 0;
+       }
 
        /* Make sure the value is valid */
        alarm_value = rk_tsadcv2_temp_to_code(table, temp);
-       if (alarm_value == table.data_mask)
-               return;
+       if (alarm_value == table->data_mask)
+               return -ERANGE;
 
-       writel_relaxed(alarm_value & table.data_mask,
+       writel_relaxed(alarm_value & table->data_mask,
                       regs + TSADCV2_COMP_INT(chn));
 
        int_en = readl_relaxed(regs + TSADCV2_INT_EN);
        int_en |= TSADCV2_INT_SRC_EN(chn);
        writel_relaxed(int_en, regs + TSADCV2_INT_EN);
+
+       return 0;
 }
 
-static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table,
-                                 int chn, void __iomem *regs, int temp)
+static int rk_tsadcv2_tshut_temp(const struct chip_tsadc_table *table,
+                                int chn, void __iomem *regs, int temp)
 {
        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;
+       if (tshut_value == table->data_mask)
+               return -ERANGE;
 
        writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn));
 
        /* TSHUT will be valid */
        val = readl_relaxed(regs + TSADCV2_AUTO_CON);
        writel_relaxed(val | TSADCV2_AUTO_SRC_EN(chn), regs + TSADCV2_AUTO_CON);
+
+       return 0;
 }
 
 static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
@@ -883,10 +924,8 @@ static int rockchip_thermal_set_trips(void *_sensor, int low, int high)
        dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n",
                __func__, sensor->id, low, high);
 
-       tsadc->set_alarm_temp(tsadc->table,
-                             sensor->id, thermal->regs, high);
-
-       return 0;
+       return tsadc->set_alarm_temp(&tsadc->table,
+                                    sensor->id, thermal->regs, high);
 }
 
 static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
@@ -896,7 +935,7 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
        const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip;
        int retval;
 
-       retval = tsadc->get_temp(tsadc->table,
+       retval = tsadc->get_temp(&tsadc->table,
                                 sensor->id, thermal->regs, out_temp);
        dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n",
                sensor->id, *out_temp, retval);
@@ -982,8 +1021,12 @@ rockchip_thermal_register_sensor(struct platform_device *pdev,
        int error;
 
        tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode);
-       tsadc->set_tshut_temp(tsadc->table, id, thermal->regs,
+
+       error = tsadc->set_tshut_temp(&tsadc->table, id, thermal->regs,
                              thermal->tshut_temp);
+       if (error)
+               dev_err(&pdev->dev, "%s: invalid tshut=%d, error=%d\n",
+                       __func__, thermal->tshut_temp, error);
 
        sensor->thermal = thermal;
        sensor->id = id;
@@ -1196,9 +1239,13 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev)
 
                thermal->chip->set_tshut_mode(id, thermal->regs,
                                              thermal->tshut_mode);
-               thermal->chip->set_tshut_temp(thermal->chip->table,
+
+               error = thermal->chip->set_tshut_temp(&thermal->chip->table,
                                              id, thermal->regs,
                                              thermal->tshut_temp);
+               if (error)
+                       dev_err(&pdev->dev, "%s: invalid tshut=%d, error=%d\n",
+                               __func__, thermal->tshut_temp, error);
        }
 
        thermal->chip->control(thermal->regs, true);