linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/5] thermal: stm32: driver improvements
@ 2019-11-04 13:30 Pascal Paillet
  2019-11-04 13:30 ` [PATCH v2 1/5] thermal: stm32: remove hardware irq handler Pascal Paillet
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Pascal Paillet @ 2019-11-04 13:30 UTC (permalink / raw)
  To: rui.zhang, edubezval, daniel.lezcano, amit.kucheria,
	mcoquelin.stm32, alexandre.torgue, p.paillet,
	david.hernandezsanchez, horms+renesas, wsa+renesas, linux-pm,
	linux-stm32, linux-arm-kernel, linux-kernel

The goal of this patchset is to improve and simplify the stm32 thermal
driver:
* remove hardware interrupt handler that is useless
* let the framewwork handle the trip points
* fix interrupt management to avoid receiving hundreds of
interrupts when the temperature is close to the low threshold.
* improve temperature reading resolution

Pascal Paillet (5):
  thermal: stm32: remove hardware irq handler
  thermal: stm32: fix icifr register name
  thermal: stm32: handle multiple trip points
  thermal: stm32: improve temperature resolution
  thermal: stm32: fix low threshold interrupt flood

 drivers/thermal/st/stm_thermal.c | 367 ++++++++++---------------------
 1 file changed, 111 insertions(+), 256 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/5] thermal: stm32: remove hardware irq handler
  2019-11-04 13:30 [PATCH v2 0/5] thermal: stm32: driver improvements Pascal Paillet
@ 2019-11-04 13:30 ` Pascal Paillet
  2019-12-04 21:05   ` Daniel Lezcano
  2019-11-04 13:30 ` [PATCH v2 2/5] thermal: stm32: fix icifr register name Pascal Paillet
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Pascal Paillet @ 2019-11-04 13:30 UTC (permalink / raw)
  To: rui.zhang, edubezval, daniel.lezcano, amit.kucheria,
	mcoquelin.stm32, alexandre.torgue, p.paillet,
	david.hernandezsanchez, horms+renesas, wsa+renesas, linux-pm,
	linux-stm32, linux-arm-kernel, linux-kernel

Remove hardware irq handler because it is not needed to disable the
interrupt before the threaded handler. The goal is to simplify
the code.

Change-Id: Ida967e8543c8dafc6a24508000f64f6405add31d
---
 drivers/thermal/st/stm_thermal.c | 25 +------------------------
 1 file changed, 1 insertion(+), 24 deletions(-)

diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
index cf9ddc52f30e..31aa63fb3db1 100644
--- a/drivers/thermal/st/stm_thermal.c
+++ b/drivers/thermal/st/stm_thermal.c
@@ -98,21 +98,10 @@ struct stm_thermal_sensor {
 	unsigned int low_temp_enabled;
 	int num_trips;
 	int irq;
-	unsigned int irq_enabled;
 	void __iomem *base;
 	int t0, fmt0, ramp_coeff;
 };
 
-static irqreturn_t stm_thermal_alarm_irq(int irq, void *sdata)
-{
-	struct stm_thermal_sensor *sensor = sdata;
-
-	disable_irq_nosync(irq);
-	sensor->irq_enabled = false;
-
-	return IRQ_WAKE_THREAD;
-}
-
 static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata)
 {
 	u32 value;
@@ -464,16 +453,6 @@ static int stm_thermal_get_temp(void *data, int *temp)
 			if (ret)
 				return ret;
 		}
-
-		/*
-		 * Re-enable alarm IRQ if temperature below critical
-		 * temperature
-		 */
-		if (!sensor->irq_enabled &&
-		    (celsius(*temp) < sensor->temp_critical)) {
-			sensor->irq_enabled = true;
-			enable_irq(sensor->irq);
-		}
 	}
 
 	return 0;
@@ -493,7 +472,7 @@ static int stm_register_irq(struct stm_thermal_sensor *sensor)
 	}
 
 	ret = devm_request_threaded_irq(dev, sensor->irq,
-					stm_thermal_alarm_irq,
+					NULL,
 					stm_thermal_alarm_irq_thread,
 					IRQF_ONESHOT,
 					dev->driver->name, sensor);
@@ -503,8 +482,6 @@ static int stm_register_irq(struct stm_thermal_sensor *sensor)
 		return ret;
 	}
 
-	sensor->irq_enabled = true;
-
 	dev_dbg(dev, "%s: thermal IRQ registered", __func__);
 
 	return 0;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 2/5] thermal: stm32: fix icifr register name
  2019-11-04 13:30 [PATCH v2 0/5] thermal: stm32: driver improvements Pascal Paillet
  2019-11-04 13:30 ` [PATCH v2 1/5] thermal: stm32: remove hardware irq handler Pascal Paillet
@ 2019-11-04 13:30 ` Pascal Paillet
  2019-11-04 13:30 ` [PATCH v2 3/5] thermal: stm32: handle multiple trip points Pascal Paillet
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Pascal Paillet @ 2019-11-04 13:30 UTC (permalink / raw)
  To: rui.zhang, edubezval, daniel.lezcano, amit.kucheria,
	mcoquelin.stm32, alexandre.torgue, p.paillet,
	david.hernandezsanchez, horms+renesas, wsa+renesas, linux-pm,
	linux-stm32, linux-arm-kernel, linux-kernel

Fix a mistake with the ICIFR register name.

Signed-off-by: Pascal Paillet <p.paillet@st.com>
---
 drivers/thermal/st/stm_thermal.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
index 31aa63fb3db1..7577242dadb4 100644
--- a/drivers/thermal/st/stm_thermal.c
+++ b/drivers/thermal/st/stm_thermal.c
@@ -30,7 +30,7 @@
 #define DTS_DR_OFFSET		0x1C
 #define DTS_SR_OFFSET		0x20
 #define DTS_ITENR_OFFSET	0x24
-#define DTS_CIFR_OFFSET		0x28
+#define DTS_ICIFR_OFFSET		0x28
 
 /* DTS_CFGR1 register mask definitions */
 #define HSREF_CLK_DIV_MASK	GENMASK(30, 24)
@@ -111,10 +111,10 @@ static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata)
 	value = readl_relaxed(sensor->base + DTS_SR_OFFSET);
 
 	if ((value & LOW_THRESHOLD) == LOW_THRESHOLD)
-		writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+		writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
 
 	if ((value & HIGH_THRESHOLD) == HIGH_THRESHOLD)
-		writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+		writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
 
 	thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);
 
@@ -336,7 +336,7 @@ static int stm_enable_irq(struct stm_thermal_sensor *sensor)
 	 */
 
 	/* Make sure LOW_THRESHOLD IT is clear before enabling */
-	writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+	writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
 
 	/* Enable IT generation for low threshold */
 	value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
@@ -345,7 +345,7 @@ static int stm_enable_irq(struct stm_thermal_sensor *sensor)
 	/* Enable the low temperature threshold if needed */
 	if (sensor->low_temp_enabled) {
 		/* Make sure HIGH_THRESHOLD IT is clear before enabling */
-		writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+		writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
 
 		/* Enable IT generation for high threshold */
 		value |= HIGH_THRESHOLD;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 3/5] thermal: stm32: handle multiple trip points
  2019-11-04 13:30 [PATCH v2 0/5] thermal: stm32: driver improvements Pascal Paillet
  2019-11-04 13:30 ` [PATCH v2 1/5] thermal: stm32: remove hardware irq handler Pascal Paillet
  2019-11-04 13:30 ` [PATCH v2 2/5] thermal: stm32: fix icifr register name Pascal Paillet
@ 2019-11-04 13:30 ` Pascal Paillet
  2019-12-05 10:50   ` Daniel Lezcano
  2019-11-04 13:30 ` [PATCH v2 4/5] thermal: stm32: improve temperature resolution Pascal Paillet
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Pascal Paillet @ 2019-11-04 13:30 UTC (permalink / raw)
  To: rui.zhang, edubezval, daniel.lezcano, amit.kucheria,
	mcoquelin.stm32, alexandre.torgue, p.paillet,
	david.hernandezsanchez, horms+renesas, wsa+renesas, linux-pm,
	linux-stm32, linux-arm-kernel, linux-kernel

Let the thermal framework handle the trip points instead
of custom code inside the driver. This leads to remove a lot
of code and simplifies the driver.
Implement set_trips callback to set the low and high thresholds,
modify irq enable and disable to handle those thresholds.

Signed-off-by: Pascal Paillet <p.paillet@st.com>
---
 drivers/thermal/st/stm_thermal.c | 283 +++++++++++--------------------
 1 file changed, 95 insertions(+), 188 deletions(-)

diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
index 7577242dadb4..cb72252f2800 100644
--- a/drivers/thermal/st/stm_thermal.c
+++ b/drivers/thermal/st/stm_thermal.c
@@ -51,10 +51,17 @@
 /* DTS_DR register mask definitions */
 #define TS1_MFREQ_MASK		GENMASK(15, 0)
 
+/* DTS_ITENR register mask definitions */
+#define ITENR_MASK		(GENMASK(2, 0) | GENMASK(6, 4))
+
+/* DTS_ICIFR register mask definitions */
+#define ICIFR_MASK		(GENMASK(2, 0) | GENMASK(6, 4))
+
 /* Less significant bit position definitions */
 #define TS1_T0_POS		16
 #define TS1_SMP_TIME_POS	16
 #define TS1_HITTHD_POS		16
+#define TS1_LITTHD_POS		0
 #define HSREF_CLK_DIV_POS	24
 
 /* DTS_CFGR1 bit definitions */
@@ -91,32 +98,28 @@ struct stm_thermal_sensor {
 	struct thermal_zone_device *th_dev;
 	enum thermal_device_mode mode;
 	struct clk *clk;
-	int high_temp;
-	int low_temp;
-	int temp_critical;
-	int temp_passive;
 	unsigned int low_temp_enabled;
-	int num_trips;
+	unsigned int high_temp_enabled;
 	int irq;
 	void __iomem *base;
 	int t0, fmt0, ramp_coeff;
 };
 
+static int stm_enable_irq(struct stm_thermal_sensor *sensor);
+
 static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata)
 {
-	u32 value;
 	struct stm_thermal_sensor *sensor = sdata;
 
-	/* read IT reason in SR and clear flags */
-	value = readl_relaxed(sensor->base + DTS_SR_OFFSET);
+	dev_dbg(sensor->dev, "sr:%d\n",
+		readl_relaxed(sensor->base + DTS_SR_OFFSET));
 
-	if ((value & LOW_THRESHOLD) == LOW_THRESHOLD)
-		writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
+	thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);
 
-	if ((value & HIGH_THRESHOLD) == HIGH_THRESHOLD)
-		writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
+	stm_enable_irq(sensor);
 
-	thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);
+	/* Acknoledge all DTS irqs */
+	writel_relaxed(ICIFR_MASK, sensor->base + DTS_ICIFR_OFFSET);
 
 	return IRQ_HANDLED;
 }
@@ -149,6 +152,8 @@ static int stm_sensor_power_on(struct stm_thermal_sensor *sensor)
 	writel_relaxed(value, sensor->base +
 		       DTS_CFGR1_OFFSET);
 
+	sensor->mode = THERMAL_DEVICE_ENABLED;
+
 	return 0;
 }
 
@@ -156,6 +161,8 @@ static int stm_sensor_power_off(struct stm_thermal_sensor *sensor)
 {
 	u32 value;
 
+	sensor->mode = THERMAL_DEVICE_DISABLED;
+
 	/* Stop measuring */
 	value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
 	value &= ~TS1_START;
@@ -277,50 +284,15 @@ static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor,
 	return 0;
 }
 
-static int stm_thermal_set_threshold(struct stm_thermal_sensor *sensor)
-{
-	u32 value, th;
-	int ret;
-
-	value = readl_relaxed(sensor->base + DTS_ITR1_OFFSET);
-
-	/* Erase threshold content */
-	value &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK);
-
-	/* Retrieve the sample threshold number th for a given temperature */
-	ret = stm_thermal_calculate_threshold(sensor, sensor->high_temp, &th);
-	if (ret)
-		return ret;
-
-	value |= th & TS1_LITTHD_MASK;
-
-	if (sensor->low_temp_enabled) {
-		/* Retrieve the sample threshold */
-		ret = stm_thermal_calculate_threshold(sensor, sensor->low_temp,
-						      &th);
-		if (ret)
-			return ret;
-
-		value |= (TS1_HITTHD_MASK  & (th << TS1_HITTHD_POS));
-	}
-
-	/* Write value on the Low interrupt threshold */
-	writel_relaxed(value, sensor->base + DTS_ITR1_OFFSET);
-
-	return 0;
-}
-
 /* Disable temperature interrupt */
 static int stm_disable_irq(struct stm_thermal_sensor *sensor)
 {
 	u32 value;
 
-	/* Disable IT generation for low and high thresholds */
+	/* Disable IT generation */
 	value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
-	writel_relaxed(value & ~(LOW_THRESHOLD | HIGH_THRESHOLD),
-		       sensor->base + DTS_ITENR_OFFSET);
-
-	dev_dbg(sensor->dev, "%s: IT disabled on sensor side", __func__);
+	value &= ~ITENR_MASK;
+	writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);
 
 	return 0;
 }
@@ -330,62 +302,67 @@ static int stm_enable_irq(struct stm_thermal_sensor *sensor)
 {
 	u32 value;
 
-	/*
-	 * Code below enables High temperature threshold using a low threshold
-	 * sampling value
-	 */
-
-	/* Make sure LOW_THRESHOLD IT is clear before enabling */
-	writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
+	dev_dbg(sensor->dev, "low:%d high:%d\n", sensor->low_temp_enabled,
+		sensor->high_temp_enabled);
 
-	/* Enable IT generation for low threshold */
+	/* Disable IT generation for low and high thresholds */
 	value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
-	value |= LOW_THRESHOLD;
-
-	/* Enable the low temperature threshold if needed */
-	if (sensor->low_temp_enabled) {
-		/* Make sure HIGH_THRESHOLD IT is clear before enabling */
-		writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
+	value &= ~(LOW_THRESHOLD | HIGH_THRESHOLD);
 
-		/* Enable IT generation for high threshold */
+	if (sensor->low_temp_enabled)
 		value |= HIGH_THRESHOLD;
-	}
 
-	/* Enable thresholds */
-	writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);
+	if (sensor->high_temp_enabled)
+		value |= LOW_THRESHOLD;
 
-	dev_dbg(sensor->dev, "%s: IT enabled on sensor side", __func__);
+	/* Enable interrupts */
+	writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);
 
 	return 0;
 }
 
-static int stm_thermal_update_threshold(struct stm_thermal_sensor *sensor)
+static int stm_thermal_set_trips(void *data, int low, int high)
 {
+	struct stm_thermal_sensor *sensor = data;
+	u32 itr1, th;
 	int ret;
 
-	sensor->mode = THERMAL_DEVICE_DISABLED;
+	dev_dbg(sensor->dev, "set trips %d <--> %d\n", low, high);
 
-	ret = stm_sensor_power_off(sensor);
-	if (ret)
-		return ret;
+	/* Erase threshold content */
+	itr1 = readl_relaxed(sensor->base + DTS_ITR1_OFFSET);
+	itr1 &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK);
 
-	ret = stm_disable_irq(sensor);
-	if (ret)
-		return ret;
+	/*
+	 * Disable low-temp if "low" is too small. As per thermal framework
+	 * API, we use -INT_MAX rather than INT_MIN.
+	 */
 
-	ret = stm_thermal_set_threshold(sensor);
-	if (ret)
-		return ret;
+	if (low > -INT_MAX) {
+		sensor->low_temp_enabled = 1;
+		ret = stm_thermal_calculate_threshold(sensor, low, &th);
+		if (ret)
+			return ret;
 
-	ret = stm_enable_irq(sensor);
-	if (ret)
-		return ret;
+		itr1 |= (TS1_HITTHD_MASK  & (th << TS1_HITTHD_POS));
+	} else {
+		sensor->low_temp_enabled = 0;
+	}
 
-	ret = stm_sensor_power_on(sensor);
-	if (ret)
-		return ret;
+	/* Disable high-temp if "high" is too big. */
+	if (high < INT_MAX) {
+		sensor->high_temp_enabled = 1;
+		ret = stm_thermal_calculate_threshold(sensor, high, &th);
+		if (ret)
+			return ret;
 
-	sensor->mode = THERMAL_DEVICE_ENABLED;
+		itr1 |= (TS1_LITTHD_MASK  & (th << TS1_LITTHD_POS));
+	} else {
+		sensor->high_temp_enabled = 0;
+	}
+
+	/* Write new threshod values*/
+	writel_relaxed(itr1, sensor->base + DTS_ITR1_OFFSET);
 
 	return 0;
 }
@@ -429,32 +406,6 @@ static int stm_thermal_get_temp(void *data, int *temp)
 	*temp = mcelsius(sensor->t0 + ((freqM - sensor->fmt0) /
 			 sensor->ramp_coeff));
 
-	dev_dbg(sensor->dev, "%s: temperature = %d millicelsius",
-		__func__, *temp);
-
-	/* Update thresholds */
-	if (sensor->num_trips > 1) {
-		/* Update alarm threshold value to next higher trip point */
-		if (sensor->high_temp == sensor->temp_passive &&
-		    celsius(*temp) >= sensor->temp_passive) {
-			sensor->high_temp = sensor->temp_critical;
-			sensor->low_temp = sensor->temp_passive;
-			sensor->low_temp_enabled = true;
-			ret = stm_thermal_update_threshold(sensor);
-			if (ret)
-				return ret;
-		}
-
-		if (sensor->high_temp == sensor->temp_critical &&
-		    celsius(*temp) < sensor->temp_passive) {
-			sensor->high_temp = sensor->temp_passive;
-			sensor->low_temp_enabled = false;
-			ret = stm_thermal_update_threshold(sensor);
-			if (ret)
-				return ret;
-		}
-	}
-
 	return 0;
 }
 
@@ -491,6 +442,8 @@ static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor)
 {
 	int ret;
 
+	stm_disable_irq(sensor);
+
 	ret = stm_sensor_power_off(sensor);
 	if (ret)
 		return ret;
@@ -503,7 +456,6 @@ static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor)
 static int stm_thermal_prepare(struct stm_thermal_sensor *sensor)
 {
 	int ret;
-	struct device *dev = sensor->dev;
 
 	ret = clk_prepare_enable(sensor->clk);
 	if (ret)
@@ -517,26 +469,8 @@ static int stm_thermal_prepare(struct stm_thermal_sensor *sensor)
 	if (ret)
 		goto thermal_unprepare;
 
-	/* Set threshold(s) for IRQ */
-	ret = stm_thermal_set_threshold(sensor);
-	if (ret)
-		goto thermal_unprepare;
-
-	ret = stm_enable_irq(sensor);
-	if (ret)
-		goto thermal_unprepare;
-
-	ret = stm_sensor_power_on(sensor);
-	if (ret) {
-		dev_err(dev, "%s: failed to power on sensor\n", __func__);
-		goto irq_disable;
-	}
-
 	return 0;
 
-irq_disable:
-	stm_disable_irq(sensor);
-
 thermal_unprepare:
 	clk_disable_unprepare(sensor->clk);
 
@@ -553,8 +487,6 @@ static int stm_thermal_suspend(struct device *dev)
 	if (ret)
 		return ret;
 
-	sensor->mode = THERMAL_DEVICE_DISABLED;
-
 	return 0;
 }
 
@@ -567,7 +499,12 @@ static int stm_thermal_resume(struct device *dev)
 	if (ret)
 		return ret;
 
-	sensor->mode = THERMAL_DEVICE_ENABLED;
+	ret = stm_sensor_power_on(sensor);
+	if (ret)
+		return ret;
+
+	thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);
+	stm_enable_irq(sensor);
 
 	return 0;
 }
@@ -577,6 +514,7 @@ SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume);
 
 static const struct thermal_zone_of_device_ops stm_tz_ops = {
 	.get_temp	= stm_thermal_get_temp,
+	.set_trips	= stm_thermal_set_trips,
 };
 
 static const struct of_device_id stm_thermal_of_match[] = {
@@ -589,9 +527,8 @@ static int stm_thermal_probe(struct platform_device *pdev)
 {
 	struct stm_thermal_sensor *sensor;
 	struct resource *res;
-	const struct thermal_trip *trip;
 	void __iomem *base;
-	int ret, i;
+	int ret;
 
 	if (!pdev->dev.of_node) {
 		dev_err(&pdev->dev, "%s: device tree node not found\n",
@@ -622,10 +559,23 @@ static int stm_thermal_probe(struct platform_device *pdev)
 		return PTR_ERR(sensor->clk);
 	}
 
-	/* Register IRQ into GIC */
-	ret = stm_register_irq(sensor);
-	if (ret)
+	stm_disable_irq(sensor);
+
+	/* Clear irq flags */
+	writel_relaxed(ICIFR_MASK, sensor->base + DTS_ICIFR_OFFSET);
+
+	/* Configure and enable HW sensor */
+	ret = stm_thermal_prepare(sensor);
+	if (ret) {
+		dev_err(&pdev->dev, "Error preprare sensor: %d\n", ret);
+		return ret;
+	}
+
+	ret = stm_sensor_power_on(sensor);
+	if (ret) {
+		dev_err(&pdev->dev, "Error power on sensor: %d\n", ret);
 		return ret;
+	}
 
 	sensor->th_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
 							      sensor,
@@ -638,53 +588,12 @@ static int stm_thermal_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	if (!sensor->th_dev->ops->get_crit_temp) {
-		/* Critical point must be provided */
-		ret = -EINVAL;
-		goto err_tz;
-	}
-
-	ret = sensor->th_dev->ops->get_crit_temp(sensor->th_dev,
-			&sensor->temp_critical);
-	if (ret) {
-		dev_err(&pdev->dev,
-			"Not able to read critical_temp: %d\n", ret);
+	/* Register IRQ into GIC */
+	ret = stm_register_irq(sensor);
+	if (ret)
 		goto err_tz;
-	}
-
-	sensor->temp_critical = celsius(sensor->temp_critical);
-
-	/* Set thresholds for IRQ */
-	sensor->high_temp = sensor->temp_critical;
-
-	trip = of_thermal_get_trip_points(sensor->th_dev);
-	sensor->num_trips = of_thermal_get_ntrips(sensor->th_dev);
-
-	/* Find out passive temperature if it exists */
-	for (i = (sensor->num_trips - 1); i >= 0;  i--) {
-		if (trip[i].type == THERMAL_TRIP_PASSIVE) {
-			sensor->temp_passive = celsius(trip[i].temperature);
-			/* Update high temperature threshold */
-			sensor->high_temp = sensor->temp_passive;
-			}
-	}
-
-	/*
-	 * Ensure low_temp_enabled flag is disabled.
-	 * By disabling low_temp_enabled, low threshold IT will not be
-	 * configured neither enabled because it is not needed as high
-	 * threshold is set on the lowest temperature trip point after
-	 * probe.
-	 */
-	sensor->low_temp_enabled = false;
 
-	/* Configure and enable HW sensor */
-	ret = stm_thermal_prepare(sensor);
-	if (ret) {
-		dev_err(&pdev->dev,
-			"Not able to enable sensor: %d\n", ret);
-		goto err_tz;
-	}
+	stm_enable_irq(sensor);
 
 	/*
 	 * Thermal_zone doesn't enable hwmon as default,
@@ -695,8 +604,6 @@ static int stm_thermal_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_tz;
 
-	sensor->mode = THERMAL_DEVICE_ENABLED;
-
 	dev_info(&pdev->dev, "%s: Driver initialized successfully\n",
 		 __func__);
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 4/5] thermal: stm32: improve temperature resolution
  2019-11-04 13:30 [PATCH v2 0/5] thermal: stm32: driver improvements Pascal Paillet
                   ` (2 preceding siblings ...)
  2019-11-04 13:30 ` [PATCH v2 3/5] thermal: stm32: handle multiple trip points Pascal Paillet
@ 2019-11-04 13:30 ` Pascal Paillet
  2019-12-05 11:03   ` Daniel Lezcano
  2019-11-04 13:30 ` [PATCH v2 5/5] thermal: stm32: fix low threshold interrupt flood Pascal Paillet
  2019-11-21 15:42 ` [PATCH v2 0/5] thermal: stm32: driver improvements Pascal PAILLET-LME
  5 siblings, 1 reply; 10+ messages in thread
From: Pascal Paillet @ 2019-11-04 13:30 UTC (permalink / raw)
  To: rui.zhang, edubezval, daniel.lezcano, amit.kucheria,
	mcoquelin.stm32, alexandre.torgue, p.paillet,
	david.hernandezsanchez, horms+renesas, wsa+renesas, linux-pm,
	linux-stm32, linux-arm-kernel, linux-kernel

Currently, the temperature is rounded by 1 or 2 degrees.
Change the way of computing to avoid rounds.
Also simplify the sampling time management.

Signed-off-by: Pascal Paillet <p.paillet@st.com>
---
 drivers/thermal/st/stm_thermal.c | 58 ++++++++------------------------
 1 file changed, 14 insertions(+), 44 deletions(-)

diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
index cb72252f2800..9986716b17c1 100644
--- a/drivers/thermal/st/stm_thermal.c
+++ b/drivers/thermal/st/stm_thermal.c
@@ -59,7 +59,6 @@
 
 /* Less significant bit position definitions */
 #define TS1_T0_POS		16
-#define TS1_SMP_TIME_POS	16
 #define TS1_HITTHD_POS		16
 #define TS1_LITTHD_POS		0
 #define HSREF_CLK_DIV_POS	24
@@ -83,15 +82,10 @@
 #define ONE_MHZ			1000000
 #define POLL_TIMEOUT		5000
 #define STARTUP_TIME		40
-#define TS1_T0_VAL0		30
-#define TS1_T0_VAL1		130
+#define TS1_T0_VAL0		30000  /* 30 celsius */
+#define TS1_T0_VAL1		130000 /* 130 celsius */
 #define NO_HW_TRIG		0
-
-/* The Thermal Framework expects millidegrees */
-#define mcelsius(temp)		((temp) * 1000)
-
-/* The Sensor expects oC degrees */
-#define celsius(temp)		((temp) / 1000)
+#define SAMPLING_TIME		15
 
 struct stm_thermal_sensor {
 	struct device *dev;
@@ -259,27 +253,17 @@ static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor,
 					   int temp, u32 *th)
 {
 	int freqM;
-	u32 sampling_time;
-
-	/* Retrieve the number of periods to sample */
-	sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) &
-			TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS;
 
 	/* Figure out the CLK_PTAT frequency for a given temperature */
-	freqM = ((temp - sensor->t0) * sensor->ramp_coeff)
-		 + sensor->fmt0;
-
-	dev_dbg(sensor->dev, "%s: freqM for threshold = %d Hz",
-		__func__, freqM);
+	freqM = ((temp - sensor->t0) * sensor->ramp_coeff) / 1000 +
+		sensor->fmt0;
 
 	/* Figure out the threshold sample number */
-	*th = clk_get_rate(sensor->clk);
+	*th = clk_get_rate(sensor->clk) * SAMPLING_TIME / freqM;
 	if (!*th)
 		return -EINVAL;
 
-	*th = *th / freqM;
-
-	*th *= sampling_time;
+	dev_dbg(sensor->dev, "freqM=%d Hz, threshold=0x%x", freqM, *th);
 
 	return 0;
 }
@@ -371,40 +355,26 @@ static int stm_thermal_set_trips(void *data, int low, int high)
 static int stm_thermal_get_temp(void *data, int *temp)
 {
 	struct stm_thermal_sensor *sensor = data;
-	u32 sampling_time;
+	u32 periods;
 	int freqM, ret;
 
 	if (sensor->mode != THERMAL_DEVICE_ENABLED)
 		return -EAGAIN;
 
-	/* Retrieve the number of samples */
-	ret = readl_poll_timeout(sensor->base + DTS_DR_OFFSET, freqM,
-				 (freqM & TS1_MFREQ_MASK), STARTUP_TIME,
-				 POLL_TIMEOUT);
-
+	/* Retrieve the number of periods sampled */
+	ret = readl_relaxed_poll_timeout(sensor->base + DTS_DR_OFFSET, periods,
+					 (periods & TS1_MFREQ_MASK),
+					 STARTUP_TIME, POLL_TIMEOUT);
 	if (ret)
 		return ret;
 
-	if (!freqM)
-		return -ENODATA;
-
-	/* Retrieve the number of periods sampled */
-	sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) &
-			TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS;
-
-	/* Figure out the number of samples per period */
-	freqM /= sampling_time;
-
 	/* Figure out the CLK_PTAT frequency */
-	freqM = clk_get_rate(sensor->clk) / freqM;
+	freqM = (clk_get_rate(sensor->clk) * SAMPLING_TIME) / periods;
 	if (!freqM)
 		return -EINVAL;
 
-	dev_dbg(sensor->dev, "%s: freqM=%d\n", __func__, freqM);
-
 	/* Figure out the temperature in mili celsius */
-	*temp = mcelsius(sensor->t0 + ((freqM - sensor->fmt0) /
-			 sensor->ramp_coeff));
+	*temp = (freqM - sensor->fmt0) * 1000 / sensor->ramp_coeff + sensor->t0;
 
 	return 0;
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 5/5] thermal: stm32: fix low threshold interrupt flood
  2019-11-04 13:30 [PATCH v2 0/5] thermal: stm32: driver improvements Pascal Paillet
                   ` (3 preceding siblings ...)
  2019-11-04 13:30 ` [PATCH v2 4/5] thermal: stm32: improve temperature resolution Pascal Paillet
@ 2019-11-04 13:30 ` Pascal Paillet
  2019-11-21 15:42 ` [PATCH v2 0/5] thermal: stm32: driver improvements Pascal PAILLET-LME
  5 siblings, 0 replies; 10+ messages in thread
From: Pascal Paillet @ 2019-11-04 13:30 UTC (permalink / raw)
  To: rui.zhang, edubezval, daniel.lezcano, amit.kucheria,
	mcoquelin.stm32, alexandre.torgue, p.paillet,
	david.hernandezsanchez, horms+renesas, wsa+renesas, linux-pm,
	linux-stm32, linux-arm-kernel, linux-kernel

With the STM32 thermal peripheral, it is not possible to dump the
temperature that has caused the interrupt.
When the temperature reaches the low threshold, we generally read
a temperature that is a little bit higher than the low threshold.
This maybe due to sampling precision, and also because the CPU becomes
hotter when it quits WFI mode.
In that case, the framework does not change the trip points. This leads
to a lot of low threshold interrupts.

The fix is to set the low threshold value 0.5 degrees Celsius
below the actual request.

The problem is not so frequent with the high threshold and it would
no be a good idea to set the threshold value higher than the request.

Signed-off-by: Pascal Paillet <p.paillet@st.com>
---
 drivers/thermal/st/stm_thermal.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
index 9986716b17c1..f7168762fbde 100644
--- a/drivers/thermal/st/stm_thermal.c
+++ b/drivers/thermal/st/stm_thermal.c
@@ -324,7 +324,8 @@ static int stm_thermal_set_trips(void *data, int low, int high)
 
 	if (low > -INT_MAX) {
 		sensor->low_temp_enabled = 1;
-		ret = stm_thermal_calculate_threshold(sensor, low, &th);
+		/* add 0.5 of hysteresis due to measurement error */
+		ret = stm_thermal_calculate_threshold(sensor, low - 500, &th);
 		if (ret)
 			return ret;
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 0/5] thermal: stm32: driver improvements
  2019-11-04 13:30 [PATCH v2 0/5] thermal: stm32: driver improvements Pascal Paillet
                   ` (4 preceding siblings ...)
  2019-11-04 13:30 ` [PATCH v2 5/5] thermal: stm32: fix low threshold interrupt flood Pascal Paillet
@ 2019-11-21 15:42 ` Pascal PAILLET-LME
  5 siblings, 0 replies; 10+ messages in thread
From: Pascal PAILLET-LME @ 2019-11-21 15:42 UTC (permalink / raw)
  To: rui.zhang, edubezval, daniel.lezcano, amit.kucheria,
	mcoquelin.stm32, Alexandre TORGUE, David HERNANDEZ SANCHEZ,
	horms+renesas, wsa+renesas, linux-pm, linux-stm32,
	linux-arm-kernel, linux-kernel


> The goal of this patchset is to improve and simplify the stm32 thermal
> driver:
> * remove hardware interrupt handler that is useless
> * let the framewwork handle the trip points
> * fix interrupt management to avoid receiving hundreds of
> interrupts when the temperature is close to the low threshold.
> * improve temperature reading resolution
gentle reminder !
> Pascal Paillet (5):
>    thermal: stm32: remove hardware irq handler
>    thermal: stm32: fix icifr register name
>    thermal: stm32: handle multiple trip points
>    thermal: stm32: improve temperature resolution
>    thermal: stm32: fix low threshold interrupt flood
>
>   drivers/thermal/st/stm_thermal.c | 367 ++++++++++---------------------
>   1 file changed, 111 insertions(+), 256 deletions(-)
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/5] thermal: stm32: remove hardware irq handler
  2019-11-04 13:30 ` [PATCH v2 1/5] thermal: stm32: remove hardware irq handler Pascal Paillet
@ 2019-12-04 21:05   ` Daniel Lezcano
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Lezcano @ 2019-12-04 21:05 UTC (permalink / raw)
  To: Pascal Paillet, rui.zhang, edubezval, amit.kucheria,
	mcoquelin.stm32, alexandre.torgue, david.hernandezsanchez,
	horms+renesas, wsa+renesas, linux-pm, linux-stm32,
	linux-arm-kernel, linux-kernel

On 04/11/2019 14:30, Pascal Paillet wrote:
> Remove hardware irq handler because it is not needed to disable the
> interrupt before the threaded handler. The goal is to simplify
> the code.

Please elaborate the explanation here. I guess all the code removed is
because of:

	/* read IT reason in SR and clear flags */
	value = readl_relaxed(sensor->base + DTS_SR_OFFSET);

Right?

> Change-Id: Ida967e8543c8dafc6a24508000f64f6405add31d

Remove Change-Id.

Missing SoB.

> ---
>  drivers/thermal/st/stm_thermal.c | 25 +------------------------
>  1 file changed, 1 insertion(+), 24 deletions(-)
> 
> diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
> index cf9ddc52f30e..31aa63fb3db1 100644
> --- a/drivers/thermal/st/stm_thermal.c
> +++ b/drivers/thermal/st/stm_thermal.c
> @@ -98,21 +98,10 @@ struct stm_thermal_sensor {
>  	unsigned int low_temp_enabled;
>  	int num_trips;
>  	int irq;
> -	unsigned int irq_enabled;
>  	void __iomem *base;
>  	int t0, fmt0, ramp_coeff;
>  };
>  
> -static irqreturn_t stm_thermal_alarm_irq(int irq, void *sdata)
> -{
> -	struct stm_thermal_sensor *sensor = sdata;
> -
> -	disable_irq_nosync(irq);
> -	sensor->irq_enabled = false;
> -
> -	return IRQ_WAKE_THREAD;
> -}
> -
>  static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata)
>  {
>  	u32 value;
> @@ -464,16 +453,6 @@ static int stm_thermal_get_temp(void *data, int *temp)
>  			if (ret)
>  				return ret;
>  		}
> -
> -		/*
> -		 * Re-enable alarm IRQ if temperature below critical
> -		 * temperature
> -		 */
> -		if (!sensor->irq_enabled &&
> -		    (celsius(*temp) < sensor->temp_critical)) {
> -			sensor->irq_enabled = true;
> -			enable_irq(sensor->irq);
> -		}
>  	}
>  
>  	return 0;
> @@ -493,7 +472,7 @@ static int stm_register_irq(struct stm_thermal_sensor *sensor)
>  	}
>  
>  	ret = devm_request_threaded_irq(dev, sensor->irq,
> -					stm_thermal_alarm_irq,
> +					NULL,
>  					stm_thermal_alarm_irq_thread,
>  					IRQF_ONESHOT,
>  					dev->driver->name, sensor);
> @@ -503,8 +482,6 @@ static int stm_register_irq(struct stm_thermal_sensor *sensor)
>  		return ret;
>  	}
>  
> -	sensor->irq_enabled = true;
> -
>  	dev_dbg(dev, "%s: thermal IRQ registered", __func__);
>  
>  	return 0;
> 


-- 
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 3/5] thermal: stm32: handle multiple trip points
  2019-11-04 13:30 ` [PATCH v2 3/5] thermal: stm32: handle multiple trip points Pascal Paillet
@ 2019-12-05 10:50   ` Daniel Lezcano
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Lezcano @ 2019-12-05 10:50 UTC (permalink / raw)
  To: Pascal Paillet, rui.zhang, edubezval, amit.kucheria,
	mcoquelin.stm32, alexandre.torgue, david.hernandezsanchez,
	horms+renesas, wsa+renesas, linux-pm, linux-stm32,
	linux-arm-kernel, linux-kernel



Hi Pascal,

On 04/11/2019 14:30, Pascal Paillet wrote:
> Let the thermal framework handle the trip points instead
> of custom code inside the driver. This leads to remove a lot
> of code and simplifies the driver.
> Implement set_trips callback to set the low and high thresholds,
> modify irq enable and disable to handle those thresholds.

there are a lot of changes in this patch, please split it into smaller
pieces with a good description.

Thanks


> Signed-off-by: Pascal Paillet <p.paillet@st.com>
> ---
>  drivers/thermal/st/stm_thermal.c | 283 +++++++++++--------------------
>  1 file changed, 95 insertions(+), 188 deletions(-)
> 
> diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
> index 7577242dadb4..cb72252f2800 100644
> --- a/drivers/thermal/st/stm_thermal.c
> +++ b/drivers/thermal/st/stm_thermal.c
> @@ -51,10 +51,17 @@
>  /* DTS_DR register mask definitions */
>  #define TS1_MFREQ_MASK		GENMASK(15, 0)
>  
> +/* DTS_ITENR register mask definitions */
> +#define ITENR_MASK		(GENMASK(2, 0) | GENMASK(6, 4))
> +
> +/* DTS_ICIFR register mask definitions */
> +#define ICIFR_MASK		(GENMASK(2, 0) | GENMASK(6, 4))
> +
>  /* Less significant bit position definitions */
>  #define TS1_T0_POS		16
>  #define TS1_SMP_TIME_POS	16
>  #define TS1_HITTHD_POS		16
> +#define TS1_LITTHD_POS		0
>  #define HSREF_CLK_DIV_POS	24
>  
>  /* DTS_CFGR1 bit definitions */
> @@ -91,32 +98,28 @@ struct stm_thermal_sensor {
>  	struct thermal_zone_device *th_dev;
>  	enum thermal_device_mode mode;
>  	struct clk *clk;
> -	int high_temp;
> -	int low_temp;
> -	int temp_critical;
> -	int temp_passive;
>  	unsigned int low_temp_enabled;
> -	int num_trips;
> +	unsigned int high_temp_enabled;
>  	int irq;
>  	void __iomem *base;
>  	int t0, fmt0, ramp_coeff;
>  };
>  
> +static int stm_enable_irq(struct stm_thermal_sensor *sensor);
> +

Move the function instead of adding a declaration.

>  static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata)
>  {
> -	u32 value;
>  	struct stm_thermal_sensor *sensor = sdata;
>  
> -	/* read IT reason in SR and clear flags */
> -	value = readl_relaxed(sensor->base + DTS_SR_OFFSET);
> +	dev_dbg(sensor->dev, "sr:%d\n",
> +		readl_relaxed(sensor->base + DTS_SR_OFFSET));
>  
> -	if ((value & LOW_THRESHOLD) == LOW_THRESHOLD)
> -		writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
> +	thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);
>  
> -	if ((value & HIGH_THRESHOLD) == HIGH_THRESHOLD)
> -		writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
> +	stm_enable_irq(sensor);
>  
> -	thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);
> +	/* Acknoledge all DTS irqs */
> +	writel_relaxed(ICIFR_MASK, sensor->base + DTS_ICIFR_OFFSET);
>  
>  	return IRQ_HANDLED;
>  }
> @@ -149,6 +152,8 @@ static int stm_sensor_power_on(struct stm_thermal_sensor *sensor)
>  	writel_relaxed(value, sensor->base +
>  		       DTS_CFGR1_OFFSET);
>  
> +	sensor->mode = THERMAL_DEVICE_ENABLED;
> +
>  	return 0;
>  }
>  
> @@ -156,6 +161,8 @@ static int stm_sensor_power_off(struct stm_thermal_sensor *sensor)
>  {
>  	u32 value;
>  
> +	sensor->mode = THERMAL_DEVICE_DISABLED;
> +
>  	/* Stop measuring */
>  	value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
>  	value &= ~TS1_START;
> @@ -277,50 +284,15 @@ static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor,
>  	return 0;
>  }
>  
> -static int stm_thermal_set_threshold(struct stm_thermal_sensor *sensor)
> -{
> -	u32 value, th;
> -	int ret;
> -
> -	value = readl_relaxed(sensor->base + DTS_ITR1_OFFSET);
> -
> -	/* Erase threshold content */
> -	value &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK);
> -
> -	/* Retrieve the sample threshold number th for a given temperature */
> -	ret = stm_thermal_calculate_threshold(sensor, sensor->high_temp, &th);
> -	if (ret)
> -		return ret;
> -
> -	value |= th & TS1_LITTHD_MASK;
> -
> -	if (sensor->low_temp_enabled) {
> -		/* Retrieve the sample threshold */
> -		ret = stm_thermal_calculate_threshold(sensor, sensor->low_temp,
> -						      &th);
> -		if (ret)
> -			return ret;
> -
> -		value |= (TS1_HITTHD_MASK  & (th << TS1_HITTHD_POS));
> -	}
> -
> -	/* Write value on the Low interrupt threshold */
> -	writel_relaxed(value, sensor->base + DTS_ITR1_OFFSET);
> -
> -	return 0;
> -}
> -
>  /* Disable temperature interrupt */
>  static int stm_disable_irq(struct stm_thermal_sensor *sensor)
>  {
>  	u32 value;
>  
> -	/* Disable IT generation for low and high thresholds */
> +	/* Disable IT generation */
>  	value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
> -	writel_relaxed(value & ~(LOW_THRESHOLD | HIGH_THRESHOLD),
> -		       sensor->base + DTS_ITENR_OFFSET);
> -
> -	dev_dbg(sensor->dev, "%s: IT disabled on sensor side", __func__);
> +	value &= ~ITENR_MASK;
> +	writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);
>  
>  	return 0;
>  }
> @@ -330,62 +302,67 @@ static int stm_enable_irq(struct stm_thermal_sensor *sensor)
>  {
>  	u32 value;
>  
> -	/*
> -	 * Code below enables High temperature threshold using a low threshold
> -	 * sampling value
> -	 */
> -
> -	/* Make sure LOW_THRESHOLD IT is clear before enabling */
> -	writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
> +	dev_dbg(sensor->dev, "low:%d high:%d\n", sensor->low_temp_enabled,
> +		sensor->high_temp_enabled);
>  
> -	/* Enable IT generation for low threshold */
> +	/* Disable IT generation for low and high thresholds */
>  	value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
> -	value |= LOW_THRESHOLD;
> -
> -	/* Enable the low temperature threshold if needed */
> -	if (sensor->low_temp_enabled) {
> -		/* Make sure HIGH_THRESHOLD IT is clear before enabling */
> -		writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_ICIFR_OFFSET);
> +	value &= ~(LOW_THRESHOLD | HIGH_THRESHOLD);
>  
> -		/* Enable IT generation for high threshold */
> +	if (sensor->low_temp_enabled)
>  		value |= HIGH_THRESHOLD;
> -	}
>  
> -	/* Enable thresholds */
> -	writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);
> +	if (sensor->high_temp_enabled)
> +		value |= LOW_THRESHOLD;
>  
> -	dev_dbg(sensor->dev, "%s: IT enabled on sensor side", __func__);
> +	/* Enable interrupts */
> +	writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);
>  
>  	return 0;
>  }
>  
> -static int stm_thermal_update_threshold(struct stm_thermal_sensor *sensor)
> +static int stm_thermal_set_trips(void *data, int low, int high)
>  {
> +	struct stm_thermal_sensor *sensor = data;
> +	u32 itr1, th;
>  	int ret;
>  
> -	sensor->mode = THERMAL_DEVICE_DISABLED;
> +	dev_dbg(sensor->dev, "set trips %d <--> %d\n", low, high);
>  
> -	ret = stm_sensor_power_off(sensor);
> -	if (ret)
> -		return ret;
> +	/* Erase threshold content */
> +	itr1 = readl_relaxed(sensor->base + DTS_ITR1_OFFSET);
> +	itr1 &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK);
>  
> -	ret = stm_disable_irq(sensor);
> -	if (ret)
> -		return ret;
> +	/*
> +	 * Disable low-temp if "low" is too small. As per thermal framework
> +	 * API, we use -INT_MAX rather than INT_MIN.
> +	 */
>  
> -	ret = stm_thermal_set_threshold(sensor);
> -	if (ret)
> -		return ret;
> +	if (low > -INT_MAX) {
> +		sensor->low_temp_enabled = 1;
> +		ret = stm_thermal_calculate_threshold(sensor, low, &th);
> +		if (ret)
> +			return ret;
>  
> -	ret = stm_enable_irq(sensor);
> -	if (ret)
> -		return ret;
> +		itr1 |= (TS1_HITTHD_MASK  & (th << TS1_HITTHD_POS));
> +	} else {
> +		sensor->low_temp_enabled = 0;
> +	}
>  
> -	ret = stm_sensor_power_on(sensor);
> -	if (ret)
> -		return ret;
> +	/* Disable high-temp if "high" is too big. */
> +	if (high < INT_MAX) {
> +		sensor->high_temp_enabled = 1;
> +		ret = stm_thermal_calculate_threshold(sensor, high, &th);
> +		if (ret)
> +			return ret;
>  
> -	sensor->mode = THERMAL_DEVICE_ENABLED;
> +		itr1 |= (TS1_LITTHD_MASK  & (th << TS1_LITTHD_POS));
> +	} else {
> +		sensor->high_temp_enabled = 0;
> +	}
> +
> +	/* Write new threshod values*/
> +	writel_relaxed(itr1, sensor->base + DTS_ITR1_OFFSET);
>  
>  	return 0;
>  }
> @@ -429,32 +406,6 @@ static int stm_thermal_get_temp(void *data, int *temp)
>  	*temp = mcelsius(sensor->t0 + ((freqM - sensor->fmt0) /
>  			 sensor->ramp_coeff));
>  
> -	dev_dbg(sensor->dev, "%s: temperature = %d millicelsius",
> -		__func__, *temp);
> -
> -	/* Update thresholds */
> -	if (sensor->num_trips > 1) {
> -		/* Update alarm threshold value to next higher trip point */
> -		if (sensor->high_temp == sensor->temp_passive &&
> -		    celsius(*temp) >= sensor->temp_passive) {
> -			sensor->high_temp = sensor->temp_critical;
> -			sensor->low_temp = sensor->temp_passive;
> -			sensor->low_temp_enabled = true;
> -			ret = stm_thermal_update_threshold(sensor);
> -			if (ret)
> -				return ret;
> -		}
> -
> -		if (sensor->high_temp == sensor->temp_critical &&
> -		    celsius(*temp) < sensor->temp_passive) {
> -			sensor->high_temp = sensor->temp_passive;
> -			sensor->low_temp_enabled = false;
> -			ret = stm_thermal_update_threshold(sensor);
> -			if (ret)
> -				return ret;
> -		}
> -	}
> -
>  	return 0;
>  }
>  
> @@ -491,6 +442,8 @@ static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor)
>  {
>  	int ret;
>  
> +	stm_disable_irq(sensor);
> +
>  	ret = stm_sensor_power_off(sensor);
>  	if (ret)
>  		return ret;
> @@ -503,7 +456,6 @@ static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor)
>  static int stm_thermal_prepare(struct stm_thermal_sensor *sensor)
>  {
>  	int ret;
> -	struct device *dev = sensor->dev;
>  
>  	ret = clk_prepare_enable(sensor->clk);
>  	if (ret)
> @@ -517,26 +469,8 @@ static int stm_thermal_prepare(struct stm_thermal_sensor *sensor)
>  	if (ret)
>  		goto thermal_unprepare;
>  
> -	/* Set threshold(s) for IRQ */
> -	ret = stm_thermal_set_threshold(sensor);
> -	if (ret)
> -		goto thermal_unprepare;
> -
> -	ret = stm_enable_irq(sensor);
> -	if (ret)
> -		goto thermal_unprepare;
> -
> -	ret = stm_sensor_power_on(sensor);
> -	if (ret) {
> -		dev_err(dev, "%s: failed to power on sensor\n", __func__);
> -		goto irq_disable;
> -	}
> -
>  	return 0;
>  
> -irq_disable:
> -	stm_disable_irq(sensor);
> -
>  thermal_unprepare:
>  	clk_disable_unprepare(sensor->clk);
>  
> @@ -553,8 +487,6 @@ static int stm_thermal_suspend(struct device *dev)
>  	if (ret)
>  		return ret;
>  
> -	sensor->mode = THERMAL_DEVICE_DISABLED;
> -
>  	return 0;
>  }
>  
> @@ -567,7 +499,12 @@ static int stm_thermal_resume(struct device *dev)
>  	if (ret)
>  		return ret;
>  
> -	sensor->mode = THERMAL_DEVICE_ENABLED;
> +	ret = stm_sensor_power_on(sensor);
> +	if (ret)
> +		return ret;
> +
> +	thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);
> +	stm_enable_irq(sensor);
>  
>  	return 0;
>  }
> @@ -577,6 +514,7 @@ SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume);
>  
>  static const struct thermal_zone_of_device_ops stm_tz_ops = {
>  	.get_temp	= stm_thermal_get_temp,
> +	.set_trips	= stm_thermal_set_trips,
>  };
>  
>  static const struct of_device_id stm_thermal_of_match[] = {
> @@ -589,9 +527,8 @@ static int stm_thermal_probe(struct platform_device *pdev)
>  {
>  	struct stm_thermal_sensor *sensor;
>  	struct resource *res;
> -	const struct thermal_trip *trip;
>  	void __iomem *base;
> -	int ret, i;
> +	int ret;
>  
>  	if (!pdev->dev.of_node) {
>  		dev_err(&pdev->dev, "%s: device tree node not found\n",
> @@ -622,10 +559,23 @@ static int stm_thermal_probe(struct platform_device *pdev)
>  		return PTR_ERR(sensor->clk);
>  	}
>  
> -	/* Register IRQ into GIC */
> -	ret = stm_register_irq(sensor);
> -	if (ret)
> +	stm_disable_irq(sensor);
> +
> +	/* Clear irq flags */
> +	writel_relaxed(ICIFR_MASK, sensor->base + DTS_ICIFR_OFFSET);
> +
> +	/* Configure and enable HW sensor */
> +	ret = stm_thermal_prepare(sensor);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Error preprare sensor: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = stm_sensor_power_on(sensor);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Error power on sensor: %d\n", ret);
>  		return ret;
> +	}
>  
>  	sensor->th_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
>  							      sensor,
> @@ -638,53 +588,12 @@ static int stm_thermal_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> -	if (!sensor->th_dev->ops->get_crit_temp) {
> -		/* Critical point must be provided */
> -		ret = -EINVAL;
> -		goto err_tz;
> -	}
> -
> -	ret = sensor->th_dev->ops->get_crit_temp(sensor->th_dev,
> -			&sensor->temp_critical);
> -	if (ret) {
> -		dev_err(&pdev->dev,
> -			"Not able to read critical_temp: %d\n", ret);
> +	/* Register IRQ into GIC */
> +	ret = stm_register_irq(sensor);
> +	if (ret)
>  		goto err_tz;
> -	}
> -
> -	sensor->temp_critical = celsius(sensor->temp_critical);
> -
> -	/* Set thresholds for IRQ */
> -	sensor->high_temp = sensor->temp_critical;
> -
> -	trip = of_thermal_get_trip_points(sensor->th_dev);
> -	sensor->num_trips = of_thermal_get_ntrips(sensor->th_dev);
> -
> -	/* Find out passive temperature if it exists */
> -	for (i = (sensor->num_trips - 1); i >= 0;  i--) {
> -		if (trip[i].type == THERMAL_TRIP_PASSIVE) {
> -			sensor->temp_passive = celsius(trip[i].temperature);
> -			/* Update high temperature threshold */
> -			sensor->high_temp = sensor->temp_passive;
> -			}
> -	}
> -
> -	/*
> -	 * Ensure low_temp_enabled flag is disabled.
> -	 * By disabling low_temp_enabled, low threshold IT will not be
> -	 * configured neither enabled because it is not needed as high
> -	 * threshold is set on the lowest temperature trip point after
> -	 * probe.
> -	 */
> -	sensor->low_temp_enabled = false;
>  
> -	/* Configure and enable HW sensor */
> -	ret = stm_thermal_prepare(sensor);
> -	if (ret) {
> -		dev_err(&pdev->dev,
> -			"Not able to enable sensor: %d\n", ret);
> -		goto err_tz;
> -	}
> +	stm_enable_irq(sensor);
>  
>  	/*
>  	 * Thermal_zone doesn't enable hwmon as default,
> @@ -695,8 +604,6 @@ static int stm_thermal_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto err_tz;
>  
> -	sensor->mode = THERMAL_DEVICE_ENABLED;
> -
>  	dev_info(&pdev->dev, "%s: Driver initialized successfully\n",
>  		 __func__);
>  
> 


-- 
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 4/5] thermal: stm32: improve temperature resolution
  2019-11-04 13:30 ` [PATCH v2 4/5] thermal: stm32: improve temperature resolution Pascal Paillet
@ 2019-12-05 11:03   ` Daniel Lezcano
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Lezcano @ 2019-12-05 11:03 UTC (permalink / raw)
  To: Pascal Paillet, rui.zhang, edubezval, amit.kucheria,
	mcoquelin.stm32, alexandre.torgue, david.hernandezsanchez,
	horms+renesas, wsa+renesas, linux-pm, linux-stm32,
	linux-arm-kernel, linux-kernel

On 04/11/2019 14:30, Pascal Paillet wrote:
> Currently, the temperature is rounded by 1 or 2 degrees.
> Change the way of computing to avoid rounds.
> Also simplify the sampling time management.

Give more details about the changes in order to let us understand them.

> Signed-off-by: Pascal Paillet <p.paillet@st.com>
> ---
>  drivers/thermal/st/stm_thermal.c | 58 ++++++++------------------------
>  1 file changed, 14 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
> index cb72252f2800..9986716b17c1 100644
> --- a/drivers/thermal/st/stm_thermal.c
> +++ b/drivers/thermal/st/stm_thermal.c
> @@ -59,7 +59,6 @@
>  
>  /* Less significant bit position definitions */
>  #define TS1_T0_POS		16
> -#define TS1_SMP_TIME_POS	16
>  #define TS1_HITTHD_POS		16
>  #define TS1_LITTHD_POS		0
>  #define HSREF_CLK_DIV_POS	24
> @@ -83,15 +82,10 @@
>  #define ONE_MHZ			1000000
>  #define POLL_TIMEOUT		5000
>  #define STARTUP_TIME		40
> -#define TS1_T0_VAL0		30
> -#define TS1_T0_VAL1		130
> +#define TS1_T0_VAL0		30000  /* 30 celsius */
> +#define TS1_T0_VAL1		130000 /* 130 celsius */
>  #define NO_HW_TRIG		0
> -
> -/* The Thermal Framework expects millidegrees */
> -#define mcelsius(temp)		((temp) * 1000)
> -
> -/* The Sensor expects oC degrees */
> -#define celsius(temp)		((temp) / 1000)
> +#define SAMPLING_TIME		15
>  
>  struct stm_thermal_sensor {
>  	struct device *dev;
> @@ -259,27 +253,17 @@ static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor,
>  					   int temp, u32 *th)
>  {
>  	int freqM;
> -	u32 sampling_time;
> -
> -	/* Retrieve the number of periods to sample */
> -	sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) &
> -			TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS;
>  
>  	/* Figure out the CLK_PTAT frequency for a given temperature */
> -	freqM = ((temp - sensor->t0) * sensor->ramp_coeff)
> -		 + sensor->fmt0;
> -
> -	dev_dbg(sensor->dev, "%s: freqM for threshold = %d Hz",
> -		__func__, freqM);
> +	freqM = ((temp - sensor->t0) * sensor->ramp_coeff) / 1000 +
> +		sensor->fmt0;
>  
>  	/* Figure out the threshold sample number */
> -	*th = clk_get_rate(sensor->clk);
> +	*th = clk_get_rate(sensor->clk) * SAMPLING_TIME / freqM;
>  	if (!*th)
>  		return -EINVAL;
>  
> -	*th = *th / freqM;
> -
> -	*th *= sampling_time;
> +	dev_dbg(sensor->dev, "freqM=%d Hz, threshold=0x%x", freqM, *th);
>  
>  	return 0;
>  }
> @@ -371,40 +355,26 @@ static int stm_thermal_set_trips(void *data, int low, int high)
>  static int stm_thermal_get_temp(void *data, int *temp)
>  {
>  	struct stm_thermal_sensor *sensor = data;
> -	u32 sampling_time;
> +	u32 periods;
>  	int freqM, ret;
>  
>  	if (sensor->mode != THERMAL_DEVICE_ENABLED)
>  		return -EAGAIN;
>  
> -	/* Retrieve the number of samples */
> -	ret = readl_poll_timeout(sensor->base + DTS_DR_OFFSET, freqM,
> -				 (freqM & TS1_MFREQ_MASK), STARTUP_TIME,
> -				 POLL_TIMEOUT);
> -
> +	/* Retrieve the number of periods sampled */
> +	ret = readl_relaxed_poll_timeout(sensor->base + DTS_DR_OFFSET, periods,
> +					 (periods & TS1_MFREQ_MASK),
> +					 STARTUP_TIME, POLL_TIMEOUT);
>  	if (ret)
>  		return ret;
>  
> -	if (!freqM)
> -		return -ENODATA;
> -
> -	/* Retrieve the number of periods sampled */
> -	sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) &
> -			TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS;
> -
> -	/* Figure out the number of samples per period */
> -	freqM /= sampling_time;
> -
>  	/* Figure out the CLK_PTAT frequency */
> -	freqM = clk_get_rate(sensor->clk) / freqM;
> +	freqM = (clk_get_rate(sensor->clk) * SAMPLING_TIME) / periods;
>  	if (!freqM)
>  		return -EINVAL;
>  
> -	dev_dbg(sensor->dev, "%s: freqM=%d\n", __func__, freqM);
> -
>  	/* Figure out the temperature in mili celsius */
> -	*temp = mcelsius(sensor->t0 + ((freqM - sensor->fmt0) /
> -			 sensor->ramp_coeff));
> +	*temp = (freqM - sensor->fmt0) * 1000 / sensor->ramp_coeff + sensor->t0;
>  
>  	return 0;
>  }
> 


-- 
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-12-05 11:03 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-04 13:30 [PATCH v2 0/5] thermal: stm32: driver improvements Pascal Paillet
2019-11-04 13:30 ` [PATCH v2 1/5] thermal: stm32: remove hardware irq handler Pascal Paillet
2019-12-04 21:05   ` Daniel Lezcano
2019-11-04 13:30 ` [PATCH v2 2/5] thermal: stm32: fix icifr register name Pascal Paillet
2019-11-04 13:30 ` [PATCH v2 3/5] thermal: stm32: handle multiple trip points Pascal Paillet
2019-12-05 10:50   ` Daniel Lezcano
2019-11-04 13:30 ` [PATCH v2 4/5] thermal: stm32: improve temperature resolution Pascal Paillet
2019-12-05 11:03   ` Daniel Lezcano
2019-11-04 13:30 ` [PATCH v2 5/5] thermal: stm32: fix low threshold interrupt flood Pascal Paillet
2019-11-21 15:42 ` [PATCH v2 0/5] thermal: stm32: driver improvements Pascal PAILLET-LME

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).