diff options
Diffstat (limited to 'drivers/thermal/qcom/tsens-common.c')
-rw-r--r-- | drivers/thermal/qcom/tsens-common.c | 159 |
1 files changed, 112 insertions, 47 deletions
diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index f80c73f11740..928e8e81ba69 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -12,18 +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 -#define SLOPE_DEFAULT 3200 - char *qfprom_read(struct device *dev, const char *cname) { struct nvmem_cell *cell; @@ -46,18 +34,18 @@ char *qfprom_read(struct device *dev, const char *cname) * and offset values are derived from tz->tzp->slope and tz->tzp->offset * resp. */ -void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1, +void compute_intercept_slope(struct tsens_priv *priv, u32 *p1, u32 *p2, u32 mode) { int i; int num, den; - for (i = 0; i < tmdev->num_sensors; i++) { - dev_dbg(tmdev->dev, + for (i = 0; i < priv->num_sensors; i++) { + dev_dbg(priv->dev, "sensor%d - data_point1:%#x data_point2:%#x\n", i, p1[i], p2[i]); - tmdev->sensor[i].slope = SLOPE_DEFAULT; + priv->sensor[i].slope = SLOPE_DEFAULT; if (mode == TWO_PT_CALIB) { /* * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ @@ -66,16 +54,30 @@ void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1, num = p2[i] - p1[i]; num *= SLOPE_FACTOR; den = CAL_DEGC_PT2 - CAL_DEGC_PT1; - tmdev->sensor[i].slope = num / den; + priv->sensor[i].slope = num / den; } - tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) - + priv->sensor[i].offset = (p1[i] * SLOPE_FACTOR) - (CAL_DEGC_PT1 * - tmdev->sensor[i].slope); - dev_dbg(tmdev->dev, "offset:%d\n", tmdev->sensor[i].offset); + priv->sensor[i].slope); + dev_dbg(priv->dev, "offset:%d\n", priv->sensor[i].offset); } } +bool is_sensor_enabled(struct tsens_priv *priv, u32 hw_id) +{ + u32 val; + int ret; + + if ((hw_id > (priv->num_sensors - 1)) || (hw_id < 0)) + return -EINVAL; + ret = regmap_field_read(priv->rf[SENSOR_EN], &val); + if (ret) + return ret; + + return val & (1 << hw_id); +} + static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) { int degc, num, den; @@ -95,18 +97,54 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) return degc; } -int get_temp_common(struct tsens_device *tmdev, int id, int *temp) +int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp) { - struct tsens_sensor *s = &tmdev->sensor[id]; - u32 code; - unsigned int status_reg; + struct tsens_sensor *s = &priv->sensor[i]; + u32 temp_idx = LAST_TEMP_0 + s->hw_id; + u32 valid_idx = VALID_0 + s->hw_id; + u32 last_temp = 0, valid, mask; + int ret; + + ret = regmap_field_read(priv->rf[valid_idx], &valid); + if (ret) + return ret; + while (!valid) { + /* Valid bit is 0 for 6 AHB clock cycles. + * At 19.2MHz, 1 AHB clock is ~60ns. + * We should enter this loop very, very rarely. + */ + ndelay(400); + ret = regmap_field_read(priv->rf[valid_idx], &valid); + if (ret) + return ret; + } + + /* Valid bit is set, OK to read the temperature */ + ret = regmap_field_read(priv->rf[temp_idx], &last_temp); + if (ret) + return ret; + + if (priv->feat->adc) { + /* Convert temperature from ADC code to milliCelsius */ + *temp = code_to_degc(last_temp, s) * 1000; + } else { + mask = GENMASK(priv->fields[LAST_TEMP_0].msb, + priv->fields[LAST_TEMP_0].lsb); + /* Convert temperature from deciCelsius to milliCelsius */ + *temp = sign_extend32(last_temp, fls(mask) - 1) * 100; + } + + return 0; +} + +int get_temp_common(struct tsens_priv *priv, int i, int *temp) +{ + struct tsens_sensor *s = &priv->sensor[i]; int last_temp = 0, ret; - status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET; - ret = regmap_read(tmdev->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; @@ -127,21 +165,21 @@ static const struct regmap_config tsens_srot_config = { .reg_stride = 4, }; -int __init init_common(struct tsens_device *tmdev) +int __init init_common(struct tsens_priv *priv) { void __iomem *tm_base, *srot_base; + struct device *dev = priv->dev; struct resource *res; - u32 code; - int ret; - struct platform_device *op = of_find_device_by_node(tmdev->dev->of_node); - u16 ctrl_offset = tmdev->reg_offsets[SROT_CTRL_OFFSET]; + u32 enabled; + int ret, i, j; + struct platform_device *op = of_find_device_by_node(priv->dev->of_node); if (!op) return -EINVAL; if (op->num_resources > 1) { /* DT with separate SROT and TM address space */ - tmdev->tm_offset = 0; + priv->tm_offset = 0; res = platform_get_resource(op, IORESOURCE_MEM, 1); srot_base = devm_ioremap_resource(&op->dev, res); if (IS_ERR(srot_base)) { @@ -149,16 +187,15 @@ int __init init_common(struct tsens_device *tmdev) goto err_put_device; } - tmdev->srot_map = devm_regmap_init_mmio(tmdev->dev, srot_base, + priv->srot_map = devm_regmap_init_mmio(dev, srot_base, &tsens_srot_config); - if (IS_ERR(tmdev->srot_map)) { - ret = PTR_ERR(tmdev->srot_map); + if (IS_ERR(priv->srot_map)) { + ret = PTR_ERR(priv->srot_map); goto err_put_device; } - } else { /* old DTs where SROT and TM were in a contiguous 2K block */ - tmdev->tm_offset = 0x1000; + priv->tm_offset = 0x1000; } res = platform_get_resource(op, IORESOURCE_MEM, 0); @@ -168,19 +205,47 @@ int __init init_common(struct tsens_device *tmdev) goto err_put_device; } - tmdev->tm_map = devm_regmap_init_mmio(tmdev->dev, tm_base, &tsens_config); - if (IS_ERR(tmdev->tm_map)) { - ret = PTR_ERR(tmdev->tm_map); + priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); + if (IS_ERR(priv->tm_map)) { + ret = PTR_ERR(priv->tm_map); goto err_put_device; } - if (tmdev->srot_map) { - ret = regmap_read(tmdev->srot_map, ctrl_offset, &code); - if (ret) + priv->rf[TSENS_EN] = devm_regmap_field_alloc(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(dev, "tsens device is not enabled\n"); + ret = -ENODEV; + goto err_put_device; + } + + priv->rf[SENSOR_EN] = devm_regmap_field_alloc(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->feat->max_sensors; i++, j++) { + priv->rf[j] = devm_regmap_field_alloc(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(tmdev->dev, "tsens device is not enabled\n"); - ret = -ENODEV; + } + } + for (i = 0, j = VALID_0; i < priv->feat->max_sensors; i++, j++) { + priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map, + priv->fields[j]); + if (IS_ERR(priv->rf[j])) { + ret = PTR_ERR(priv->rf[j]); goto err_put_device; } } |