Skip to content

Commit

Permalink
drivers: thermal: tsens: Introduce reg_fields to deal with register d…
Browse files Browse the repository at this point in the history
…escription

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>
  • Loading branch information
Amit Kucheria authored and Eduardo Valentin committed May 14, 2019
1 parent 582a0c4 commit c199705
Show file tree
Hide file tree
Showing 5 changed files with 370 additions and 58 deletions.
62 changes: 39 additions & 23 deletions drivers/thermal/qcom/tsens-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,6 @@
#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
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
}
Expand Down
50 changes: 48 additions & 2 deletions drivers/thermal/qcom/tsens-v0_1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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 = {
Expand All @@ -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,
};
105 changes: 82 additions & 23 deletions drivers/thermal/qcom/tsens-v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -61,19 +81,58 @@ static int get_temp_tsens_v2(struct tsens_priv *priv, int id, int *temp)
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,
};
5 changes: 2 additions & 3 deletions drivers/thermal/qcom/tsens.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit c199705

Please sign in to comment.