OSDN Git Service

drivers: thermal: tsens: Introduce reg_fields to deal with register description
authorAmit Kucheria <amit.kucheria@linaro.org>
Wed, 20 Mar 2019 13:17:50 +0000 (18:47 +0530)
committerEduardo Valentin <edubezval@gmail.com>
Tue, 14 May 2019 13:59:12 +0000 (06:59 -0700)
As we add support for newer versions of the TSENS IP, the current
approach isn't scaling because registers and bitfields get moved around,
requiring platform-specific hacks in the code. By moving to regmap, we
can hide the register level differences away from the code.

Define a common set of registers and bit-fields that we care about
across the various tsens IP versions.

Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
drivers/thermal/qcom/tsens-common.c
drivers/thermal/qcom/tsens-v0_1.c
drivers/thermal/qcom/tsens-v2.c
drivers/thermal/qcom/tsens.c
drivers/thermal/qcom/tsens.h

index f0ef4e3..0f9deec 100644 (file)
 #include <linux/regmap.h>
 #include "tsens.h"
 
-/* SROT */
-#define TSENS_EN               BIT(0)
-
-/* TM */
-#define STATUS_OFFSET          0x30
-#define SN_ADDR_OFFSET         0x4
-#define SN_ST_TEMP_MASK                0x3ff
 #define CAL_DEGC_PT1           30
 #define CAL_DEGC_PT2           120
 #define SLOPE_FACTOR           1000
@@ -95,18 +88,14 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
        return degc;
 }
 
-int get_temp_common(struct tsens_priv *priv, int id, int *temp)
+int get_temp_common(struct tsens_priv *priv, int i, int *temp)
 {
-       struct tsens_sensor *s = &priv->sensor[id];
-       u32 code;
-       unsigned int status_reg;
+       struct tsens_sensor *s = &priv->sensor[i];
        int last_temp = 0, ret;
 
-       status_reg = priv->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET;
-       ret = regmap_read(priv->tm_map, status_reg, &code);
+       ret = regmap_field_read(priv->rf[LAST_TEMP_0 + s->hw_id], &last_temp);
        if (ret)
                return ret;
-       last_temp = code & SN_ST_TEMP_MASK;
 
        *temp = code_to_degc(last_temp, s) * 1000;
 
@@ -131,10 +120,9 @@ int __init init_common(struct tsens_priv *priv)
 {
        void __iomem *tm_base, *srot_base;
        struct resource *res;
-       u32 code;
-       int ret;
+       u32 enabled;
+       int ret, i, j;
        struct platform_device *op = of_find_device_by_node(priv->dev->of_node);
-       u16 ctrl_offset = priv->reg_offsets[SROT_CTRL_OFFSET];
 
        if (!op)
                return -EINVAL;
@@ -173,13 +161,41 @@ int __init init_common(struct tsens_priv *priv)
                goto err_put_device;
        }
 
-       if (priv->srot_map) {
-               ret = regmap_read(priv->srot_map, ctrl_offset, &code);
-               if (ret)
+       priv->rf[TSENS_EN] = devm_regmap_field_alloc(priv->dev, priv->srot_map,
+                                                    priv->fields[TSENS_EN]);
+       if (IS_ERR(priv->rf[TSENS_EN])) {
+               ret = PTR_ERR(priv->rf[TSENS_EN]);
+               goto err_put_device;
+       }
+       ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
+       if (ret)
+               goto err_put_device;
+       if (!enabled) {
+               dev_err(priv->dev, "tsens device is not enabled\n");
+               ret = -ENODEV;
+               goto err_put_device;
+       }
+
+       priv->rf[SENSOR_EN] = devm_regmap_field_alloc(priv->dev, priv->srot_map,
+                                                     priv->fields[SENSOR_EN]);
+       if (IS_ERR(priv->rf[SENSOR_EN])) {
+               ret = PTR_ERR(priv->rf[SENSOR_EN]);
+               goto err_put_device;
+       }
+       /* now alloc regmap_fields in tm_map */
+       for (i = 0, j = LAST_TEMP_0; i < priv->num_sensors; i++, j++) {
+               priv->rf[j] = devm_regmap_field_alloc(priv->dev, priv->tm_map,
+                                                     priv->fields[j]);
+               if (IS_ERR(priv->rf[j])) {
+                       ret = PTR_ERR(priv->rf[j]);
                        goto err_put_device;
-               if (!(code & TSENS_EN)) {
-                       dev_err(priv->dev, "tsens device is not enabled\n");
-                       ret = -ENODEV;
+               }
+       }
+       for (i = 0, j = VALID_0; i < priv->num_sensors; i++, j++) {
+               priv->rf[j] = devm_regmap_field_alloc(priv->dev, priv->tm_map,
+                                                     priv->fields[j]);
+               if (IS_ERR(priv->rf[j])) {
+                       ret = PTR_ERR(priv->rf[j]);
                        goto err_put_device;
                }
        }
index a6e26be..a7560e9 100644 (file)
@@ -6,6 +6,15 @@
 #include <linux/platform_device.h>
 #include "tsens.h"
 
+/* ----- SROT ------ */
+#define SROT_CTRL_OFF 0x0000
+
+/* ----- TM ------ */
+#define TM_INT_EN_OFF                          0x0000
+#define TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF      0x0004
+#define TM_Sn_STATUS_OFF                       0x0030
+#define TM_TRDY_OFF                            0x005c
+
 /* eeprom layout data for 8916 */
 #define MSM8916_BASE0_MASK     0x0000007f
 #define MSM8916_BASE1_MASK     0xfe000000
@@ -308,6 +317,40 @@ static int calibrate_8974(struct tsens_priv *priv)
        return 0;
 }
 
+/* v0.1: 8916, 8974 */
+
+static const struct tsens_features tsens_v0_1_feat = {
+       .ver_major      = VER_0_1,
+       .crit_int       = 0,
+       .adc            = 1,
+       .srot_split     = 1,
+};
+
+static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = {
+       /* ----- SROT ------ */
+       /* No VERSION information */
+
+       /* CTRL_OFFSET */
+       [TSENS_EN]     = REG_FIELD(SROT_CTRL_OFF, 0,  0),
+       [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1,  1),
+
+       /* ----- TM ------ */
+       /* INTERRUPT ENABLE */
+       [INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 0),
+
+       /* Sn_STATUS */
+       REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP,    TM_Sn_STATUS_OFF,  0,  9),
+       /* No VALID field on v0.1 */
+       REG_FIELD_FOR_EACH_SENSOR11(MIN_STATUS,   TM_Sn_STATUS_OFF, 10, 10),
+       REG_FIELD_FOR_EACH_SENSOR11(LOWER_STATUS, TM_Sn_STATUS_OFF, 11, 11),
+       REG_FIELD_FOR_EACH_SENSOR11(UPPER_STATUS, TM_Sn_STATUS_OFF, 12, 12),
+       /* No CRITICAL field on v0.1 */
+       REG_FIELD_FOR_EACH_SENSOR11(MAX_STATUS,   TM_Sn_STATUS_OFF, 13, 13),
+
+       /* TRDY: 1=ready, 0=in progress */
+       [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
+};
+
 static const struct tsens_ops ops_8916 = {
        .init           = init_common,
        .calibrate      = calibrate_8916,
@@ -317,8 +360,10 @@ static const struct tsens_ops ops_8916 = {
 const struct tsens_plat_data data_8916 = {
        .num_sensors    = 5,
        .ops            = &ops_8916,
-       .reg_offsets    = { [SROT_CTRL_OFFSET] = 0x0 },
        .hw_ids         = (unsigned int []){0, 1, 2, 4, 5 },
+
+       .feat           = &tsens_v0_1_feat,
+       .fields = tsens_v0_1_regfields,
 };
 
 static const struct tsens_ops ops_8974 = {
@@ -330,5 +375,6 @@ static const struct tsens_ops ops_8974 = {
 const struct tsens_plat_data data_8974 = {
        .num_sensors    = 11,
        .ops            = &ops_8974,
-       .reg_offsets    = { [SROT_CTRL_OFFSET] = 0x0 },
+       .feat           = &tsens_v0_1_feat,
+       .fields = tsens_v0_1_regfields,
 };
index 8b70077..b58f5af 100644 (file)
@@ -4,50 +4,70 @@
  * Copyright (c) 2018, Linaro Limited
  */
 
-#include <linux/regmap.h>
 #include <linux/bitops.h>
+#include <linux/regmap.h>
 #include "tsens.h"
 
-#define STATUS_OFFSET          0xa0
+/* ----- SROT ------ */
+#define SROT_HW_VER_OFF        0x0000
+#define SROT_CTRL_OFF          0x0004
+
+/* ----- TM ------ */
+#define TM_INT_EN_OFF                  0x0004
+#define TM_UPPER_LOWER_INT_STATUS_OFF  0x0008
+#define TM_UPPER_LOWER_INT_CLEAR_OFF   0x000c
+#define TM_UPPER_LOWER_INT_MASK_OFF    0x0010
+#define TM_CRITICAL_INT_STATUS_OFF     0x0014
+#define TM_CRITICAL_INT_CLEAR_OFF      0x0018
+#define TM_CRITICAL_INT_MASK_OFF       0x001c
+#define TM_Sn_UPPER_LOWER_THRESHOLD_OFF 0x0020
+#define TM_Sn_CRITICAL_THRESHOLD_OFF   0x0060
+#define TM_Sn_STATUS_OFF               0x00a0
+#define TM_TRDY_OFF                    0x00e4
+
 #define LAST_TEMP_MASK         0xfff
-#define STATUS_VALID_BIT       BIT(21)
 
 static int get_temp_tsens_v2(struct tsens_priv *priv, int id, int *temp)
 {
        struct tsens_sensor *s = &priv->sensor[id];
-       u32 code;
-       unsigned int status_reg;
-       u32 last_temp = 0, last_temp2 = 0, last_temp3 = 0;
+       u32 temp_idx = LAST_TEMP_0 + s->hw_id;
+       u32 valid_idx = VALID_0 + s->hw_id;
+       u32 last_temp = 0, last_temp2 = 0, last_temp3 = 0, valid;
        int ret;
 
-       status_reg = priv->tm_offset + STATUS_OFFSET + s->hw_id * 4;
-       ret = regmap_read(priv->tm_map, status_reg, &code);
+       ret = regmap_field_read(priv->rf[temp_idx], &last_temp);
+       if (ret)
+               return ret;
+
+       ret = regmap_field_read(priv->rf[valid_idx], &valid);
        if (ret)
                return ret;
-       last_temp = code & LAST_TEMP_MASK;
-       if (code & STATUS_VALID_BIT)
+
+       if (valid)
                goto done;
 
        /* Try a second time */
-       ret = regmap_read(priv->tm_map, status_reg, &code);
+       ret = regmap_field_read(priv->rf[valid_idx], &valid);
+       if (ret)
+               return ret;
+       ret = regmap_field_read(priv->rf[temp_idx], &last_temp2);
        if (ret)
                return ret;
-       if (code & STATUS_VALID_BIT) {
-               last_temp = code & LAST_TEMP_MASK;
+       if (valid) {
+               last_temp = last_temp2;
                goto done;
-       } else {
-               last_temp2 = code & LAST_TEMP_MASK;
        }
 
        /* Try a third/last time */
-       ret = regmap_read(priv->tm_map, status_reg, &code);
+       ret = regmap_field_read(priv->rf[valid_idx], &valid);
        if (ret)
                return ret;
-       if (code & STATUS_VALID_BIT) {
-               last_temp = code & LAST_TEMP_MASK;
+       ret = regmap_field_read(priv->rf[temp_idx], &last_temp3);
+       if (ret)
+               return ret;
+       if (valid) {
+               last_temp = last_temp3;
                goto done;
-       } else {
-               last_temp3 = code & LAST_TEMP_MASK;
        }
 
        if (last_temp == last_temp2)
@@ -61,19 +81,58 @@ done:
        return 0;
 }
 
+/* v2.x: 8996, 8998, sdm845 */
+
+static const struct tsens_features tsens_v2_feat = {
+       .ver_major      = VER_2_X,
+       .crit_int       = 1,
+       .adc            = 0,
+       .srot_split     = 1,
+};
+
+static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
+       /* ----- SROT ------ */
+       /* VERSION */
+       [VER_MAJOR] = REG_FIELD(SROT_HW_VER_OFF, 28, 31),
+       [VER_MINOR] = REG_FIELD(SROT_HW_VER_OFF, 16, 27),
+       [VER_STEP]  = REG_FIELD(SROT_HW_VER_OFF,  0, 15),
+       /* CTRL_OFF */
+       [TSENS_EN]     = REG_FIELD(SROT_CTRL_OFF,    0,  0),
+       [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF,    1,  1),
+
+       /* ----- TM ------ */
+       /* INTERRUPT ENABLE */
+       /* v2 has separate enables for UPPER/LOWER/CRITICAL interrupts */
+       [INT_EN]  = REG_FIELD(TM_INT_EN_OFF, 0, 2),
+
+       /* Sn_STATUS */
+       REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP,       TM_Sn_STATUS_OFF,  0,  11),
+       REG_FIELD_FOR_EACH_SENSOR16(VALID,           TM_Sn_STATUS_OFF, 21,  21),
+       REG_FIELD_FOR_EACH_SENSOR16(MIN_STATUS,      TM_Sn_STATUS_OFF, 16,  16),
+       REG_FIELD_FOR_EACH_SENSOR16(LOWER_STATUS,    TM_Sn_STATUS_OFF, 17,  17),
+       REG_FIELD_FOR_EACH_SENSOR16(UPPER_STATUS,    TM_Sn_STATUS_OFF, 18,  18),
+       REG_FIELD_FOR_EACH_SENSOR16(CRITICAL_STATUS, TM_Sn_STATUS_OFF, 19,  19),
+       REG_FIELD_FOR_EACH_SENSOR16(MAX_STATUS,      TM_Sn_STATUS_OFF, 20,  20),
+
+       /* TRDY: 1=ready, 0=in progress */
+       [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
+};
+
 static const struct tsens_ops ops_generic_v2 = {
        .init           = init_common,
        .get_temp       = get_temp_tsens_v2,
 };
 
 const struct tsens_plat_data data_tsens_v2 = {
-       .ops            = &ops_generic_v2,
-       .reg_offsets    = { [SROT_CTRL_OFFSET] = 0x4 },
+       .ops            = &ops_generic_v2,
+       .feat           = &tsens_v2_feat,
+       .fields = tsens_v2_regfields,
 };
 
 /* Kept around for backward compatibility with old msm8996.dtsi */
 const struct tsens_plat_data data_8996 = {
        .num_sensors    = 13,
        .ops            = &ops_generic_v2,
-       .reg_offsets    = { [SROT_CTRL_OFFSET] = 0x4 },
+       .feat           = &tsens_v2_feat,
+       .fields = tsens_v2_regfields,
 };
index 0b5be08..b91a0b8 100644 (file)
@@ -144,9 +144,8 @@ static int tsens_probe(struct platform_device *pdev)
                else
                        priv->sensor[i].hw_id = i;
        }
-       for (i = 0; i < REG_ARRAY_SIZE; i++) {
-               priv->reg_offsets[i] = data->reg_offsets[i];
-       }
+       priv->feat = data->feat;
+       priv->fields = data->fields;
 
        if (!priv->ops || !priv->ops->init || !priv->ops->get_temp)
                return -EINVAL;
index 27b8f74..a9390e0 100644 (file)
 #define TWO_PT_CALIB           0x3
 
 #include <linux/thermal.h>
+#include <linux/regmap.h>
 
 struct tsens_priv;
 
+enum tsens_ver {
+       VER_0_1 = 0,
+       VER_1_X,
+       VER_2_X,
+};
+
 /**
  * struct tsens_sensor - data for each sensor connected to the tsens device
  * @priv: tsens device instance that this sensor is connected to
@@ -58,10 +65,189 @@ struct tsens_ops {
        int (*get_trend)(struct tsens_priv *priv, int i, enum thermal_trend *trend);
 };
 
-enum reg_list {
-       SROT_CTRL_OFFSET,
+#define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \
+       [_name##_##0]  = REG_FIELD(_offset,      _startbit, _stopbit),  \
+       [_name##_##1]  = REG_FIELD(_offset +  4, _startbit, _stopbit), \
+       [_name##_##2]  = REG_FIELD(_offset +  8, _startbit, _stopbit), \
+       [_name##_##3]  = REG_FIELD(_offset + 12, _startbit, _stopbit), \
+       [_name##_##4]  = REG_FIELD(_offset + 16, _startbit, _stopbit), \
+       [_name##_##5]  = REG_FIELD(_offset + 20, _startbit, _stopbit), \
+       [_name##_##6]  = REG_FIELD(_offset + 24, _startbit, _stopbit), \
+       [_name##_##7]  = REG_FIELD(_offset + 28, _startbit, _stopbit), \
+       [_name##_##8]  = REG_FIELD(_offset + 32, _startbit, _stopbit), \
+       [_name##_##9]  = REG_FIELD(_offset + 36, _startbit, _stopbit), \
+       [_name##_##10] = REG_FIELD(_offset + 40, _startbit, _stopbit)
+
+#define REG_FIELD_FOR_EACH_SENSOR16(_name, _offset, _startbit, _stopbit) \
+       [_name##_##0]  = REG_FIELD(_offset,      _startbit, _stopbit),  \
+       [_name##_##1]  = REG_FIELD(_offset +  4, _startbit, _stopbit), \
+       [_name##_##2]  = REG_FIELD(_offset +  8, _startbit, _stopbit), \
+       [_name##_##3]  = REG_FIELD(_offset + 12, _startbit, _stopbit), \
+       [_name##_##4]  = REG_FIELD(_offset + 16, _startbit, _stopbit), \
+       [_name##_##5]  = REG_FIELD(_offset + 20, _startbit, _stopbit), \
+       [_name##_##6]  = REG_FIELD(_offset + 24, _startbit, _stopbit), \
+       [_name##_##7]  = REG_FIELD(_offset + 28, _startbit, _stopbit), \
+       [_name##_##8]  = REG_FIELD(_offset + 32, _startbit, _stopbit), \
+       [_name##_##9]  = REG_FIELD(_offset + 36, _startbit, _stopbit), \
+       [_name##_##10] = REG_FIELD(_offset + 40, _startbit, _stopbit), \
+       [_name##_##11] = REG_FIELD(_offset + 44, _startbit, _stopbit), \
+       [_name##_##12] = REG_FIELD(_offset + 48, _startbit, _stopbit), \
+       [_name##_##13] = REG_FIELD(_offset + 52, _startbit, _stopbit), \
+       [_name##_##14] = REG_FIELD(_offset + 56, _startbit, _stopbit), \
+       [_name##_##15] = REG_FIELD(_offset + 60, _startbit, _stopbit)
+
+/* reg_field IDs to use as an index into an array */
+enum regfield_ids {
+       /* ----- SROT ------ */
+       /* HW_VER */
+       VER_MAJOR = 0,
+       VER_MINOR,
+       VER_STEP,
+       /* CTRL_OFFSET */
+       TSENS_EN =  3,
+       TSENS_SW_RST,
+       SENSOR_EN,
+       CODE_OR_TEMP,
+
+       /* ----- TM ------ */
+       /* STATUS */
+       LAST_TEMP_0 = 7,        /* Last temperature reading */
+       LAST_TEMP_1,
+       LAST_TEMP_2,
+       LAST_TEMP_3,
+       LAST_TEMP_4,
+       LAST_TEMP_5,
+       LAST_TEMP_6,
+       LAST_TEMP_7,
+       LAST_TEMP_8,
+       LAST_TEMP_9,
+       LAST_TEMP_10,
+       LAST_TEMP_11,
+       LAST_TEMP_12,
+       LAST_TEMP_13,
+       LAST_TEMP_14,
+       LAST_TEMP_15,
+       VALID_0 = 23,           /* VALID reading or not */
+       VALID_1,
+       VALID_2,
+       VALID_3,
+       VALID_4,
+       VALID_5,
+       VALID_6,
+       VALID_7,
+       VALID_8,
+       VALID_9,
+       VALID_10,
+       VALID_11,
+       VALID_12,
+       VALID_13,
+       VALID_14,
+       VALID_15,
+       MIN_STATUS_0,           /* MIN threshold violated */
+       MIN_STATUS_1,
+       MIN_STATUS_2,
+       MIN_STATUS_3,
+       MIN_STATUS_4,
+       MIN_STATUS_5,
+       MIN_STATUS_6,
+       MIN_STATUS_7,
+       MIN_STATUS_8,
+       MIN_STATUS_9,
+       MIN_STATUS_10,
+       MIN_STATUS_11,
+       MIN_STATUS_12,
+       MIN_STATUS_13,
+       MIN_STATUS_14,
+       MIN_STATUS_15,
+       MAX_STATUS_0,           /* MAX threshold violated */
+       MAX_STATUS_1,
+       MAX_STATUS_2,
+       MAX_STATUS_3,
+       MAX_STATUS_4,
+       MAX_STATUS_5,
+       MAX_STATUS_6,
+       MAX_STATUS_7,
+       MAX_STATUS_8,
+       MAX_STATUS_9,
+       MAX_STATUS_10,
+       MAX_STATUS_11,
+       MAX_STATUS_12,
+       MAX_STATUS_13,
+       MAX_STATUS_14,
+       MAX_STATUS_15,
+       LOWER_STATUS_0, /* LOWER threshold violated */
+       LOWER_STATUS_1,
+       LOWER_STATUS_2,
+       LOWER_STATUS_3,
+       LOWER_STATUS_4,
+       LOWER_STATUS_5,
+       LOWER_STATUS_6,
+       LOWER_STATUS_7,
+       LOWER_STATUS_8,
+       LOWER_STATUS_9,
+       LOWER_STATUS_10,
+       LOWER_STATUS_11,
+       LOWER_STATUS_12,
+       LOWER_STATUS_13,
+       LOWER_STATUS_14,
+       LOWER_STATUS_15,
+       UPPER_STATUS_0, /* UPPER threshold violated */
+       UPPER_STATUS_1,
+       UPPER_STATUS_2,
+       UPPER_STATUS_3,
+       UPPER_STATUS_4,
+       UPPER_STATUS_5,
+       UPPER_STATUS_6,
+       UPPER_STATUS_7,
+       UPPER_STATUS_8,
+       UPPER_STATUS_9,
+       UPPER_STATUS_10,
+       UPPER_STATUS_11,
+       UPPER_STATUS_12,
+       UPPER_STATUS_13,
+       UPPER_STATUS_14,
+       UPPER_STATUS_15,
+       CRITICAL_STATUS_0,      /* CRITICAL threshold violated */
+       CRITICAL_STATUS_1,
+       CRITICAL_STATUS_2,
+       CRITICAL_STATUS_3,
+       CRITICAL_STATUS_4,
+       CRITICAL_STATUS_5,
+       CRITICAL_STATUS_6,
+       CRITICAL_STATUS_7,
+       CRITICAL_STATUS_8,
+       CRITICAL_STATUS_9,
+       CRITICAL_STATUS_10,
+       CRITICAL_STATUS_11,
+       CRITICAL_STATUS_12,
+       CRITICAL_STATUS_13,
+       CRITICAL_STATUS_14,
+       CRITICAL_STATUS_15,
+       /* TRDY */
+       TRDY,
+       /* INTERRUPT ENABLE */
+       INT_EN, /* Pre-V1, V1.x */
+       LOW_INT_EN,     /* V2.x */
+       UP_INT_EN,      /* V2.x */
+       CRIT_INT_EN,    /* V2.x */
 
-       REG_ARRAY_SIZE,
+       /* Keep last */
+       MAX_REGFIELDS
+};
+
+/**
+ * struct tsens_features - Features supported by the IP
+ * @ver_major: Major number of IP version
+ * @crit_int: does the IP support critical interrupts?
+ * @adc:      do the sensors only output adc code (instead of temperature)?
+ * @srot_split: does the IP neatly splits the register space into SROT and TM,
+ *              with SROT only being available to secure boot firmware?
+ */
+struct tsens_features {
+       unsigned int ver_major;
+       unsigned int crit_int:1;
+       unsigned int adc:1;
+       unsigned int srot_split:1;
 };
 
 /**
@@ -69,13 +255,15 @@ enum reg_list {
  * @num_sensors: Number of sensors supported by platform
  * @ops: operations the tsens instance supports
  * @hw_ids: Subset of sensors ids supported by platform, if not the first n
- * @reg_offsets: Register offsets for commonly used registers
+ * @feat: features of the IP
+ * @fields: bitfield locations
  */
 struct tsens_plat_data {
        const u32               num_sensors;
        const struct tsens_ops  *ops;
-       const u16               reg_offsets[REG_ARRAY_SIZE];
        unsigned int            *hw_ids;
+       const struct tsens_features     *feat;
+       const struct reg_field          *fields;
 };
 
 /**
@@ -94,8 +282,10 @@ struct tsens_context {
  * @srot_map: pointer to SROT register address space
  * @tm_offset: deal with old device trees that don't address TM and SROT
  *             address space separately
- * @reg_offsets: array of offsets to important regs for this version of IP
+ * @rf: array of regmap_fields used to store value of the field
  * @ctx: registers to be saved and restored during suspend/resume
+ * @feat: features of the IP
+ * @fields: bitfield locations
  * @ops: pointer to list of callbacks supported by this device
  * @sensor: list of sensors attached to this device
  */
@@ -105,8 +295,10 @@ struct tsens_priv {
        struct regmap                   *tm_map;
        struct regmap                   *srot_map;
        u32                             tm_offset;
-       u16                             reg_offsets[REG_ARRAY_SIZE];
+       struct regmap_field             *rf[MAX_REGFIELDS];
        struct tsens_context            ctx;
+       const struct tsens_features     *feat;
+       const struct reg_field          *fields;
        const struct tsens_ops          *ops;
        struct tsens_sensor             sensor[0];
 };