thermal/drivers/tsens: Support using nvmem cells for calibration data
authorDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Sun, 1 Jan 2023 19:40:23 +0000 (21:40 +0200)
committerDaniel Lezcano <daniel.lezcano@linaro.org>
Mon, 16 Jan 2023 10:22:30 +0000 (11:22 +0100)
Add a unified function using nvmem cells for parsing the calibration
data rather than parsing the calibration blob manually.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20230101194034.831222-10-dmitry.baryshkov@linaro.org
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
drivers/thermal/qcom/tsens-v0_1.c
drivers/thermal/qcom/tsens-v1.c
drivers/thermal/qcom/tsens.c
drivers/thermal/qcom/tsens.h

index 579028ea48f4f71fd8afcdf2749cdda940c34e5a..6c9e491f955925a887007e067a2fa3319e1869b4 100644 (file)
@@ -229,6 +229,11 @@ static int calibrate_8916(struct tsens_priv *priv)
        u32 p1[5], p2[5];
        int mode = 0;
        u32 *qfprom_cdata, *qfprom_csel;
+       int ret;
+
+       ret = tsens_calibrate_nvmem(priv, 3);
+       if (!ret)
+               return 0;
 
        qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
        if (IS_ERR(qfprom_cdata))
@@ -286,6 +291,11 @@ static int calibrate_8939(struct tsens_priv *priv)
        int mode = 0;
        u32 *qfprom_cdata;
        u32 cdata[4];
+       int ret;
+
+       ret = tsens_calibrate_common(priv);
+       if (!ret)
+               return 0;
 
        qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
        if (IS_ERR(qfprom_cdata))
@@ -486,6 +496,11 @@ static int calibrate_9607(struct tsens_priv *priv)
        u32 p1[5], p2[5];
        int mode = 0;
        u32 *qfprom_cdata;
+       int ret;
+
+       ret = tsens_calibrate_common(priv);
+       if (!ret)
+               return 0;
 
        qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
        if (IS_ERR(qfprom_cdata))
index 83c2853546d0b3286759ee429622f53471d3461e..5bba75a845c59022c3a31b85dc1a241f6a6a5673 100644 (file)
@@ -143,7 +143,11 @@ static int calibrate_v1(struct tsens_priv *priv)
        u32 p1[10], p2[10];
        u32 mode = 0, lsb = 0, msb = 0;
        u32 *qfprom_cdata;
-       int i;
+       int i, ret;
+
+       ret = tsens_calibrate_common(priv);
+       if (!ret)
+               return 0;
 
        qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
        if (IS_ERR(qfprom_cdata))
@@ -209,6 +213,11 @@ static int calibrate_8976(struct tsens_priv *priv)
        u32 p1[11], p2[11];
        int mode = 0, tmp = 0;
        u32 *qfprom_cdata;
+       int ret;
+
+       ret = tsens_calibrate_common(priv);
+       if (!ret)
+               return 0;
 
        qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
        if (IS_ERR(qfprom_cdata))
index b191e19df93dc8aee39fe9ae27571176d8041550..ce568a68de4aa0705a6fe1558c38376983966101 100644 (file)
@@ -70,6 +70,82 @@ char *qfprom_read(struct device *dev, const char *cname)
        return ret;
 }
 
+int tsens_calibrate_nvmem(struct tsens_priv *priv, int shift)
+{
+       u32 mode;
+       u32 base1, base2;
+       u32 p1[MAX_SENSORS], p2[MAX_SENSORS];
+       char name[] = "sXX_pY"; /* s10_p1 */
+       int i, ret;
+
+       if (priv->num_sensors > MAX_SENSORS)
+               return -EINVAL;
+
+       ret = nvmem_cell_read_variable_le_u32(priv->dev, "mode", &mode);
+       if (ret == -ENOENT)
+               dev_warn(priv->dev, "Please migrate to separate nvmem cells for calibration data\n");
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(priv->dev, "calibration mode is %d\n", mode);
+
+       ret = nvmem_cell_read_variable_le_u32(priv->dev, "base1", &base1);
+       if (ret < 0)
+               return ret;
+
+       ret = nvmem_cell_read_variable_le_u32(priv->dev, "base2", &base2);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < priv->num_sensors; i++) {
+               ret = snprintf(name, sizeof(name), "s%d_p1", priv->sensor[i].hw_id);
+               if (ret < 0)
+                       return ret;
+
+               ret = nvmem_cell_read_variable_le_u32(priv->dev, name, &p1[i]);
+               if (ret)
+                       return ret;
+
+               ret = snprintf(name, sizeof(name), "s%d_p2", priv->sensor[i].hw_id);
+               if (ret < 0)
+                       return ret;
+
+               ret = nvmem_cell_read_variable_le_u32(priv->dev, name, &p2[i]);
+               if (ret)
+                       return ret;
+       }
+
+       switch (mode) {
+       case ONE_PT_CALIB:
+               for (i = 0; i < priv->num_sensors; i++)
+                       p1[i] = p1[i] + (base1 << shift);
+               break;
+       case TWO_PT_CALIB:
+               for (i = 0; i < priv->num_sensors; i++)
+                       p2[i] = (p2[i] + base2) << shift;
+               fallthrough;
+       case ONE_PT_CALIB2:
+               for (i = 0; i < priv->num_sensors; i++)
+                       p1[i] = (p1[i] + base1) << shift;
+               break;
+       default:
+               dev_dbg(priv->dev, "calibrationless mode\n");
+               for (i = 0; i < priv->num_sensors; i++) {
+                       p1[i] = 500;
+                       p2[i] = 780;
+               }
+       }
+
+       compute_intercept_slope(priv, p1, p2, mode);
+
+       return 0;
+}
+
+int tsens_calibrate_common(struct tsens_priv *priv)
+{
+       return tsens_calibrate_nvmem(priv, 2);
+}
+
 /*
  * Use this function on devices where slope and offset calculations
  * depend on calibration data read from qfprom. On others the slope
index 7dd5fc2468945e3038de8e5c4c25955456fd5cbe..645ae02438fa03278aeddfa808d7fe4a01df69a0 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef __QCOM_TSENS_H__
 #define __QCOM_TSENS_H__
 
+#define NO_PT_CALIB            0x0
 #define ONE_PT_CALIB           0x1
 #define ONE_PT_CALIB2          0x2
 #define TWO_PT_CALIB           0x3
@@ -17,6 +18,8 @@
 #define THRESHOLD_MAX_ADC_CODE 0x3ff
 #define THRESHOLD_MIN_ADC_CODE 0x0
 
+#define MAX_SENSORS 16
+
 #include <linux/interrupt.h>
 #include <linux/thermal.h>
 #include <linux/regmap.h>
@@ -582,6 +585,8 @@ struct tsens_priv {
 };
 
 char *qfprom_read(struct device *dev, const char *cname);
+int tsens_calibrate_nvmem(struct tsens_priv *priv, int shift);
+int tsens_calibrate_common(struct tsens_priv *priv);
 void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mode);
 int init_common(struct tsens_priv *priv);
 int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp);