Commit 53e2a20e authored by Christian Marangi's avatar Christian Marangi Committed by Daniel Lezcano
Browse files

thermal/drivers/tsens: Add VER_0 tsens version



VER_0 is used to describe device based on tsens version before v0.1.
These device are devices based on msm8960 for example apq8064 or
ipq806x. Add support for VER_0 in tsens.c and set the right tsens feat
in tsens-8960.c file.

Signed-off-by: default avatarAnsuel Smith <ansuelsmth@gmail.com>
Reviewed-by: default avatarThara Gopinath <thara.gopinath@linaro.org>
Reported-by: default avatarkernel test robot <lkp@intel.com>
Reported-by: default avatarDan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20210420183343.2272-4-ansuelsmth@gmail.com
parent a0ed1411
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -347,8 +347,17 @@ static const struct tsens_ops ops_8960 = {
	.resume		= resume_8960,
};

static struct tsens_features tsens_8960_feat = {
	.ver_major	= VER_0,
	.crit_int	= 0,
	.adc		= 1,
	.srot_split	= 0,
	.max_sensors	= 11,
};

struct tsens_plat_data data_8960 = {
	.num_sensors	= 11,
	.ops		= &ops_8960,
	.feat		= &tsens_8960_feat,
	.fields		= tsens_8960_regfields,
};
+121 −29
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/regmap.h>
@@ -516,6 +517,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
			dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
				hw_id, __func__, temp);
		}

		if (tsens_version(priv) < VER_0_1) {
			/* Constraint: There is only 1 interrupt control register for all
			 * 11 temperature sensor. So monitoring more than 1 sensor based
			 * on interrupts will yield inconsistent result. To overcome this
			 * issue we will monitor only sensor 0 which is the master sensor.
			 */
			break;
		}
	}

	return IRQ_HANDLED;
@@ -531,6 +541,13 @@ static int tsens_set_trips(void *_sensor, int low, int high)
	int high_val, low_val, cl_high, cl_low;
	u32 hw_id = s->hw_id;

	if (tsens_version(priv) < VER_0_1) {
		/* Pre v0.1 IP had a single register for each type of interrupt
		 * and thresholds
		 */
		hw_id = 0;
	}

	dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
		hw_id, __func__, low, high);

@@ -585,6 +602,8 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
	u32 valid;
	int ret;

	/* VER_0 doesn't have VALID bit */
	if (tsens_version(priv) >= VER_0_1) {
		ret = regmap_field_read(priv->rf[valid_idx], &valid);
		if (ret)
			return ret;
@@ -598,6 +617,7 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
			if (ret)
				return ret;
		}
	}

	/* Valid bit is set, OK to read the temperature */
	*temp = tsens_hw_to_mC(s, temp_idx);
@@ -609,7 +629,18 @@ int get_temp_common(const struct tsens_sensor *s, int *temp)
{
	struct tsens_priv *priv = s->priv;
	int hw_id = s->hw_id;
	int last_temp = 0, ret;
	int last_temp = 0, ret, trdy;
	unsigned long timeout;

	timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
	do {
		if (tsens_version(priv) == VER_0) {
			ret = regmap_field_read(priv->rf[TRDY], &trdy);
			if (ret)
				return ret;
			if (!trdy)
				continue;
		}

		ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp);
		if (ret)
@@ -618,6 +649,9 @@ int get_temp_common(const struct tsens_sensor *s, int *temp)
		*temp = code_to_degc(last_temp, s) * 1000;

		return 0;
	} while (time_before(jiffies, timeout));

	return -ETIMEDOUT;
}

#ifdef CONFIG_DEBUG_FS
@@ -739,6 +773,7 @@ int __init init_common(struct tsens_priv *priv)
		priv->tm_offset = 0x1000;
	}

	if (tsens_version(priv) >= VER_0_1) {
		res = platform_get_resource(op, IORESOURCE_MEM, 0);
		tm_base = devm_ioremap_resource(dev, res);
		if (IS_ERR(tm_base)) {
@@ -747,11 +782,25 @@ int __init init_common(struct tsens_priv *priv)
		}

		priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
	if (IS_ERR(priv->tm_map)) {
	} else { /* VER_0 share the same gcc regs using a syscon */
		struct device *parent = priv->dev->parent;

		if (parent)
			priv->tm_map = syscon_node_to_regmap(parent->of_node);
	}

	if (IS_ERR_OR_NULL(priv->tm_map)) {
		if (!priv->tm_map)
			ret = -ENODEV;
		else
			ret = PTR_ERR(priv->tm_map);
		goto err_put_device;
	}

	/* VER_0 have only tm_map */
	if (!priv->srot_map)
		priv->srot_map = priv->tm_map;

	if (tsens_version(priv) > VER_0_1) {
		for (i = VER_MAJOR; i <= VER_STEP; i++) {
			priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map,
@@ -772,6 +821,10 @@ int __init init_common(struct tsens_priv *priv)
		ret = PTR_ERR(priv->rf[TSENS_EN]);
		goto err_put_device;
	}
	/* in VER_0 TSENS need to be explicitly enabled */
	if (tsens_version(priv) == VER_0)
		regmap_field_write(priv->rf[TSENS_EN], 1);

	ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
	if (ret)
		goto err_put_device;
@@ -794,6 +847,19 @@ int __init init_common(struct tsens_priv *priv)
		goto err_put_device;
	}

	priv->rf[TSENS_SW_RST] =
		devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]);
	if (IS_ERR(priv->rf[TSENS_SW_RST])) {
		ret = PTR_ERR(priv->rf[TSENS_SW_RST]);
		goto err_put_device;
	}

	priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]);
	if (IS_ERR(priv->rf[TRDY])) {
		ret = PTR_ERR(priv->rf[TRDY]);
		goto err_put_device;
	}

	/* This loop might need changes if enum regfield_ids is reordered */
	for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) {
		for (i = 0; i < priv->feat->max_sensors; i++) {
@@ -809,7 +875,7 @@ int __init init_common(struct tsens_priv *priv)
		}
	}

	if (priv->feat->crit_int) {
	if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) {
		/* Loop might need changes if enum regfield_ids is reordered */
		for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) {
			for (i = 0; i < priv->feat->max_sensors; i++) {
@@ -847,7 +913,11 @@ int __init init_common(struct tsens_priv *priv)
	}

	spin_lock_init(&priv->ul_lock);

	/* VER_0 interrupt doesn't need to be enabled */
	if (tsens_version(priv) >= VER_0_1)
		tsens_enable_irq(priv);

	tsens_debug_init(op);

err_put_device:
@@ -949,10 +1019,19 @@ static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
		if (irq == -ENXIO)
			ret = 0;
	} else {
		/* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */
		if (tsens_version(priv) == VER_0)
			ret = devm_request_threaded_irq(&pdev->dev, irq,
						NULL, thread_fn,
						IRQF_ONESHOT,
						dev_name(&pdev->dev), priv);
							thread_fn, NULL,
							IRQF_TRIGGER_RISING,
							dev_name(&pdev->dev),
							priv);
		else
			ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
							thread_fn, IRQF_ONESHOT,
							dev_name(&pdev->dev),
							priv);

		if (ret)
			dev_err(&pdev->dev, "%s: failed to get irq\n",
				__func__);
@@ -981,6 +1060,19 @@ static int tsens_register(struct tsens_priv *priv)
			priv->ops->enable(priv, i);
	}

	/* VER_0 require to set MIN and MAX THRESH
	 * These 2 regs are set using the:
	 * - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C
	 * - CRIT_THRESH_1 for MIN THRESH hardcoded to   0°C
	 */
	if (tsens_version(priv) < VER_0_1) {
		regmap_field_write(priv->rf[CRIT_THRESH_0],
				   tsens_mC_to_hw(priv->sensor, 120000));

		regmap_field_write(priv->rf[CRIT_THRESH_1],
				   tsens_mC_to_hw(priv->sensor, 0));
	}

	ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
	if (ret < 0)
		return ret;
+3 −1
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#define CAL_DEGC_PT2		120
#define SLOPE_FACTOR		1000
#define SLOPE_DEFAULT		3200
#define TIMEOUT_US		100
#define THRESHOLD_MAX_ADC_CODE	0x3ff
#define THRESHOLD_MIN_ADC_CODE	0x0

@@ -25,7 +26,8 @@ struct tsens_priv;

/* IP version numbers in ascending order */
enum tsens_ver {
	VER_0_1 = 0,
	VER_0 = 0,
	VER_0_1,
	VER_1_X,
	VER_2_X,
};