LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH RFC 0/4] drivers/thermal: support for multiple TZ for sensor
@ 2018-05-08 17:48 Lina Iyer
  2018-05-08 17:48 ` [PATCH RFC 1/4] drivers: of-thermal: abstract sensor related information Lina Iyer
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Lina Iyer @ 2018-05-08 17:48 UTC (permalink / raw)
  To: edubezval, rui.zhang
  Cc: linux-pm, linux-kernel, linux-arm-msm, daniel.lezcano,
	amit.kucheria, Lina Iyer

This is an attempt at introducing multiple thermal zones for each thermal
sensor. The usecase behind this is that, a sensor may involved in monitoring a
region that could have different mitigative actions. For example, a sensor
placed between audio and camera IP, will involve different mitigative actions
on these blocks. Sometimes it is also desirable to employ different governors
and different mitigative strategies for the same sensor. For example, using
step-wise governor for temperatures > 0 and a userspace governor for
temperatures < 0 degC.

The idea presented in this patchset involves linking thermal zones together
that share the same underlying sensor. The sensor still interacts with one
thermal zone that we deem as the primary thermal sensor. The low thresholds set
on a sensor is the max of min thresholds for the high trip threshold while the
low trip thresholds for the sensor is the min of max thresholds from the
different thermal zones of the sensor around the current sensor temperature.
When the sensor temperature crosses the threshold, the thermal zone is notified
and the new thresholds is evaluated again.

These patches continue to return a struct thermal_zone * back to the sensor
when the sensor registers. While this prevents breaking the existing
interaction, it is not very clean and optimal. This is something to think about
as we review the patches. The breakdown of the patches in this set is -

- Patch #1 refactors the current data structures to help with the new support
- Patch #2 allows probing and set up of multiple thermal zones when a sensor is
  registered.
- Patch #3 aggregates across multiple thermal zones to figure out the mitigation
  and set new thresholds on the sensor. Sensor low and high thresholds are set
  based on thresholds from any thermal zone of the sensor.
- Patch #4 notifies the framework and the related thermal zones when the sensor
  is tripped

Please consider reviewing these patches. We have seen benefits of this idea and
is implemented and used in mobile products.

Lina Iyer (4):
  drivers: of-thermal: abstract sensor related information
  drivers: of-thermal: allow multiple thermal zones for a sensor
  drivers: of-thermal: aggregate sensor trips across thermal zones
  drivers: of-thermal: notify framework when sensor is tripped

 drivers/thermal/of-thermal.c      | 205 ++++++++++++++++++++++++++----
 drivers/thermal/thermal_helpers.c |  37 +++---
 include/linux/thermal.h           |  10 ++
 3 files changed, 209 insertions(+), 43 deletions(-)

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH RFC 1/4] drivers: of-thermal: abstract sensor related information
  2018-05-08 17:48 [PATCH RFC 0/4] drivers/thermal: support for multiple TZ for sensor Lina Iyer
@ 2018-05-08 17:48 ` Lina Iyer
  2018-05-08 17:48 ` [PATCH RFC 2/4] drivers: of-thermal: allow multiple thermal zones for a sensor Lina Iyer
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Lina Iyer @ 2018-05-08 17:48 UTC (permalink / raw)
  To: edubezval, rui.zhang
  Cc: linux-pm, linux-kernel, linux-arm-msm, daniel.lezcano,
	amit.kucheria, Lina Iyer, Ram Chandrasekar

Sensor related information like the sensor callback ops and sensor data
live in the thermal zone data structure along with other parameters.
In preparation to use the same sensor across multiple thermal zones
separate out the sensor specific information into its own data
structure.

Signed-off-by: Ram Chandrasekar <rkumbako@codeaurora.org>
Signed-off-by: Lina Iyer <ilina@codeaurora.org>
---
 drivers/thermal/of-thermal.c | 72 ++++++++++++++++++++++++------------
 1 file changed, 49 insertions(+), 23 deletions(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index eea2fce82bf7..b402edd09ed1 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -35,6 +35,16 @@ struct __thermal_bind_params {
 	unsigned long max;
 };
 
+/**
+ * struct thermal_sensor - Holds individual sensor data
+ * @sensor_data: sensor driver private data passed as input argument
+ * @ops: sensor driver ops
+ */
+struct thermal_sensor {
+	void *sensor_data;
+	const struct thermal_zone_of_device_ops *ops;
+};
+
 /**
  * struct __thermal_zone - internal representation of a thermal zone
  * @mode: current thermal zone device mode (enabled/disabled)
@@ -46,8 +56,7 @@ struct __thermal_bind_params {
  * @trips: an array of trip points (0..ntrips - 1)
  * @num_tbps: number of thermal bind params
  * @tbps: an array of thermal bind params (0..num_tbps - 1)
- * @sensor_data: sensor private data used while reading temperature and trend
- * @ops: set of callbacks to handle the thermal zone based on DT
+ * @sensor: sensor related parameters
  */
 
 struct __thermal_zone {
@@ -66,8 +75,7 @@ struct __thermal_zone {
 	struct __thermal_bind_params *tbps;
 
 	/* sensor interface */
-	void *sensor_data;
-	const struct thermal_zone_of_device_ops *ops;
+	struct thermal_sensor *sensor;
 };
 
 /***   DT thermal zone device callbacks   ***/
@@ -76,22 +84,24 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
 			       int *temp)
 {
 	struct __thermal_zone *data = tz->devdata;
+	struct thermal_sensor *sensor = data->sensor;
 
-	if (!data->ops->get_temp)
+	if (!sensor || !sensor->ops->get_temp)
 		return -EINVAL;
 
-	return data->ops->get_temp(data->sensor_data, temp);
+	return sensor->ops->get_temp(sensor->sensor_data, temp);
 }
 
 static int of_thermal_set_trips(struct thermal_zone_device *tz,
 				int low, int high)
 {
 	struct __thermal_zone *data = tz->devdata;
+	struct thermal_sensor *sensor = data->sensor;
 
-	if (!data->ops || !data->ops->set_trips)
+	if (!sensor || !sensor->ops->set_trips)
 		return -EINVAL;
 
-	return data->ops->set_trips(data->sensor_data, low, high);
+	return sensor->ops->set_trips(sensor->sensor_data, low, high);
 }
 
 /**
@@ -173,19 +183,24 @@ static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
 				    int temp)
 {
 	struct __thermal_zone *data = tz->devdata;
+	struct thermal_sensor *sensor = data->sensor;
+
+	if (!sensor || !sensor->ops->set_emul_temp)
+		return -EINVAL;
 
-	return data->ops->set_emul_temp(data->sensor_data, temp);
+	return sensor->ops->set_emul_temp(sensor->sensor_data, temp);
 }
 
 static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
 				enum thermal_trend *trend)
 {
 	struct __thermal_zone *data = tz->devdata;
+	struct thermal_sensor *sensor = data->sensor;
 
-	if (!data->ops->get_trend)
+	if (!sensor || !sensor->ops->get_trend)
 		return -EINVAL;
 
-	return data->ops->get_trend(data->sensor_data, trip, trend);
+	return sensor->ops->get_trend(sensor->sensor_data, trip, trend);
 }
 
 static int of_thermal_bind(struct thermal_zone_device *thermal,
@@ -303,14 +318,16 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
 				    int temp)
 {
 	struct __thermal_zone *data = tz->devdata;
+	struct thermal_sensor *sensor = data->sensor;
 
 	if (trip >= data->ntrips || trip < 0)
 		return -EDOM;
 
-	if (data->ops->set_trip_temp) {
+	if (sensor && sensor->ops->set_trip_temp) {
 		int ret;
 
-		ret = data->ops->set_trip_temp(data->sensor_data, trip, temp);
+		ret = sensor->ops->set_trip_temp(sensor->sensor_data,
+						trip, temp);
 		if (ret)
 			return ret;
 	}
@@ -382,8 +399,8 @@ static struct thermal_zone_device_ops of_thermal_ops = {
 
 static struct thermal_zone_device *
 thermal_zone_of_add_sensor(struct device_node *zone,
-			   struct device_node *sensor, void *data,
-			   const struct thermal_zone_of_device_ops *ops)
+			   struct device_node *sensor_np,
+			   struct thermal_sensor *sensor)
 {
 	struct thermal_zone_device *tzd;
 	struct __thermal_zone *tz;
@@ -394,12 +411,11 @@ thermal_zone_of_add_sensor(struct device_node *zone,
 
 	tz = tzd->devdata;
 
-	if (!ops)
+	if (!sensor->ops)
 		return ERR_PTR(-EINVAL);
 
 	mutex_lock(&tzd->lock);
-	tz->ops = ops;
-	tz->sensor_data = data;
+	tz->sensor = sensor;
 
 	tzd->ops->get_temp = of_thermal_get_temp;
 	tzd->ops->get_trend = of_thermal_get_trend;
@@ -408,10 +424,10 @@ thermal_zone_of_add_sensor(struct device_node *zone,
 	 * The thermal zone core will calculate the window if they have set the
 	 * optional set_trips pointer.
 	 */
-	if (ops->set_trips)
+	if (sensor->ops->set_trips)
 		tzd->ops->set_trips = of_thermal_set_trips;
 
-	if (ops->set_emul_temp)
+	if (sensor->ops->set_emul_temp)
 		tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
 
 	mutex_unlock(&tzd->lock);
@@ -457,6 +473,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 {
 	struct device_node *np, *child, *sensor_np;
 	struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
+	struct thermal_sensor *sensor = NULL;
 
 	np = of_find_node_by_name(NULL, "thermal-zones");
 	if (!np)
@@ -467,6 +484,13 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 		return ERR_PTR(-EINVAL);
 	}
 
+	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+	if (!sensor) {
+		of_node_put(np);
+		return ERR_PTR(-ENOMEM);
+	}
+	sensor->sensor_data = data;
+	sensor->ops = ops;
 	sensor_np = of_node_get(dev->of_node);
 
 	for_each_available_child_of_node(np, child) {
@@ -491,7 +515,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 
 		if (sensor_specs.np == sensor_np && id == sensor_id) {
 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
-							 data, ops);
+							 sensor);
 			if (!IS_ERR(tzd))
 				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
 
@@ -505,6 +529,8 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 	of_node_put(sensor_np);
 	of_node_put(np);
 
+	if (tzd == ERR_PTR(-ENODEV))
+		kfree(sensor);
 	return tzd;
 }
 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_register);
@@ -543,8 +569,8 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
 	tzd->ops->get_trend = NULL;
 	tzd->ops->set_emul_temp = NULL;
 
-	tz->ops = NULL;
-	tz->sensor_data = NULL;
+	kfree(tz->sensor);
+	tz->sensor = NULL;
 	mutex_unlock(&tzd->lock);
 }
 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH RFC 2/4] drivers: of-thermal: allow multiple thermal zones for a sensor
  2018-05-08 17:48 [PATCH RFC 0/4] drivers/thermal: support for multiple TZ for sensor Lina Iyer
  2018-05-08 17:48 ` [PATCH RFC 1/4] drivers: of-thermal: abstract sensor related information Lina Iyer
@ 2018-05-08 17:48 ` Lina Iyer
  2018-05-08 17:48 ` [PATCH RFC 3/4] drivers: of-thermal: aggregate sensor trips across thermal zones Lina Iyer
  2018-05-08 17:48 ` [PATCH RFC 4/4] drivers: of-thermal: notify framework when sensor is tripped Lina Iyer
  3 siblings, 0 replies; 5+ messages in thread
From: Lina Iyer @ 2018-05-08 17:48 UTC (permalink / raw)
  To: edubezval, rui.zhang
  Cc: linux-pm, linux-kernel, linux-arm-msm, daniel.lezcano,
	amit.kucheria, Lina Iyer

To allow different mitigative actions based on a sensor temperature, it
is desirable to have multiple thermal zones share the same source. The
thermal zones could have different thresholds, mitigative actions and
even different governors.

Signed-off-by: Lina Iyer <ilina@codeaurora.org>
---
 drivers/thermal/of-thermal.c | 32 ++++++++++++++++++++++++++------
 include/linux/thermal.h      |  2 ++
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index b402edd09ed1..06e581a37c67 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -39,10 +39,14 @@ struct __thermal_bind_params {
  * struct thermal_sensor - Holds individual sensor data
  * @sensor_data: sensor driver private data passed as input argument
  * @ops: sensor driver ops
+ * @tz_list: list of thermal zones for this sensor
+ * @lock: lock sensor during operations
  */
 struct thermal_sensor {
 	void *sensor_data;
 	const struct thermal_zone_of_device_ops *ops;
+	struct list_head tz_list;
+	struct mutex lock;
 };
 
 /**
@@ -430,11 +434,24 @@ thermal_zone_of_add_sensor(struct device_node *zone,
 	if (sensor->ops->set_emul_temp)
 		tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
 
+	mutex_lock(&sensor->lock);
+	list_add_tail(&tzd->sensor_tzd, &sensor->tz_list);
+	mutex_unlock(&sensor->lock);
 	mutex_unlock(&tzd->lock);
 
 	return tzd;
 }
 
+static struct thermal_zone_device *
+thermal_zone_of_get_sensor_tzd(struct thermal_sensor *sensor)
+{
+	if (list_empty(&sensor->tz_list))
+		return ERR_PTR(-ENODEV);
+
+	return list_first_entry(&sensor->tz_list, struct thermal_zone_device,
+				sensor_tzd);
+}
+
 /**
  * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone
  * @dev: a valid struct device pointer of a sensor device. Must contain
@@ -460,12 +477,11 @@ thermal_zone_of_add_sensor(struct device_node *zone,
  * 01 - This function must enqueue the new sensor instead of using
  * it as the only source of temperature values.
  *
- * 02 - There must be a way to match the sensor with all thermal zones
- * that refer to it.
- *
  * Return: On success returns a valid struct thermal_zone_device,
  * otherwise, it returns a corresponding ERR_PTR(). Caller must
  * check the return value with help of IS_ERR() helper.
+ * The returned thermal_zone_device is one of the thermal zones that is
+ * using this sensor as the temeprature source.
  */
 struct thermal_zone_device *
 thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
@@ -489,6 +505,8 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 		of_node_put(np);
 		return ERR_PTR(-ENOMEM);
 	}
+	INIT_LIST_HEAD(&sensor->tz_list);
+	mutex_init(&sensor->lock);
 	sensor->sensor_data = data;
 	sensor->ops = ops;
 	sensor_np = of_node_get(dev->of_node);
@@ -521,14 +539,14 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 
 			of_node_put(sensor_specs.np);
 			of_node_put(child);
-			goto exit;
 		}
 		of_node_put(sensor_specs.np);
 	}
-exit:
+
 	of_node_put(sensor_np);
 	of_node_put(np);
 
+	tzd = thermal_zone_of_get_sensor_tzd(sensor);
 	if (tzd == ERR_PTR(-ENODEV))
 		kfree(sensor);
 	return tzd;
@@ -569,7 +587,9 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
 	tzd->ops->get_trend = NULL;
 	tzd->ops->set_emul_temp = NULL;
 
-	kfree(tz->sensor);
+	list_del(&tzd->sensor_tzd);
+	if (list_empty(&tz->sensor->tz_list))
+		kfree(tz->sensor);
 	tz->sensor = NULL;
 	mutex_unlock(&tzd->lock);
 }
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 7a133bd6ff86..09e1669a4919 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -188,6 +188,7 @@ struct thermal_attr {
  * @node:	node in thermal_tz_list (in thermal_core.c)
  * @poll_queue:	delayed work for polling
  * @notify_event: Last notification event
+ * @sensor_tzd:		node in sensor's list of thermal zone devices
  */
 struct thermal_zone_device {
 	int id;
@@ -220,6 +221,7 @@ struct thermal_zone_device {
 	struct list_head node;
 	struct delayed_work poll_queue;
 	enum thermal_notify_event notify_event;
+	struct list_head sensor_tzd;
 };
 
 /**
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH RFC 3/4] drivers: of-thermal: aggregate sensor trips across thermal zones
  2018-05-08 17:48 [PATCH RFC 0/4] drivers/thermal: support for multiple TZ for sensor Lina Iyer
  2018-05-08 17:48 ` [PATCH RFC 1/4] drivers: of-thermal: abstract sensor related information Lina Iyer
  2018-05-08 17:48 ` [PATCH RFC 2/4] drivers: of-thermal: allow multiple thermal zones for a sensor Lina Iyer
@ 2018-05-08 17:48 ` Lina Iyer
  2018-05-08 17:48 ` [PATCH RFC 4/4] drivers: of-thermal: notify framework when sensor is tripped Lina Iyer
  3 siblings, 0 replies; 5+ messages in thread
From: Lina Iyer @ 2018-05-08 17:48 UTC (permalink / raw)
  To: edubezval, rui.zhang
  Cc: linux-pm, linux-kernel, linux-arm-msm, daniel.lezcano,
	amit.kucheria, Lina Iyer

Aggregate thermal trip based on the trip points of the thermal zones
that use this sensor as the source.

Signed-off-by: Lina Iyer <ilina@codeaurora.org>
---
 drivers/thermal/of-thermal.c      | 28 ++++++++++++++++++++++-
 drivers/thermal/thermal_helpers.c | 37 ++++++++++++++++++-------------
 include/linux/thermal.h           |  4 ++++
 3 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 06e581a37c67..6fb2eeb5b6cf 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -96,16 +96,42 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
 	return sensor->ops->get_temp(sensor->sensor_data, temp);
 }
 
+static void __of_thermal_agg_trip(struct thermal_sensor *sensor,
+				 int *floor, int *ceil)
+{
+	int low, high;
+	int max_lo = INT_MIN;
+	int min_hi = INT_MAX;
+	struct thermal_zone_device *tz;
+
+	list_for_each_entry(tz, &sensor->tz_list, sensor_tzd) {
+		thermal_zone_get_trip(tz, &low, &high);
+		if (low > max_lo)
+			max_lo = low;
+		if (high < min_hi)
+			min_hi = high;
+	}
+
+	*floor = max_lo;
+	*ceil = min_hi;
+}
+
 static int of_thermal_set_trips(struct thermal_zone_device *tz,
 				int low, int high)
 {
 	struct __thermal_zone *data = tz->devdata;
 	struct thermal_sensor *sensor = data->sensor;
+	int ret;
 
 	if (!sensor || !sensor->ops->set_trips)
 		return -EINVAL;
 
-	return sensor->ops->set_trips(sensor->sensor_data, low, high);
+	mutex_lock(&sensor->lock);
+	__of_thermal_agg_trip(sensor, &low, &high);
+	ret = sensor->ops->set_trips(sensor->sensor_data, low, high);
+	mutex_unlock(&sensor->lock);
+
+	return ret;
 }
 
 /**
diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c
index f550fdee0f9b..d4fa125f8799 100644
--- a/drivers/thermal/thermal_helpers.c
+++ b/drivers/thermal/thermal_helpers.c
@@ -113,32 +113,39 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
 }
 EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
 
-void thermal_zone_set_trips(struct thermal_zone_device *tz)
+
+void thermal_zone_get_trip(struct thermal_zone_device *tz, int *low, int *high)
 {
-	int low = -INT_MAX;
-	int high = INT_MAX;
-	int trip_temp, hysteresis;
-	int i, ret;
+	int i, trip_low, trip_temp, hysteresis;
 
-	mutex_lock(&tz->lock);
-
-	if (!tz->ops->set_trips || !tz->ops->get_trip_hyst)
-		goto exit;
+	*low = -INT_MAX;
+	*high = INT_MAX;
 
 	for (i = 0; i < tz->trips; i++) {
-		int trip_low;
-
 		tz->ops->get_trip_temp(tz, i, &trip_temp);
 		tz->ops->get_trip_hyst(tz, i, &hysteresis);
 
 		trip_low = trip_temp - hysteresis;
 
-		if (trip_low < tz->temperature && trip_low > low)
-			low = trip_low;
+		if (trip_low < tz->temperature && trip_low > *low)
+			*low = trip_low;
 
-		if (trip_temp > tz->temperature && trip_temp < high)
-			high = trip_temp;
+		if (trip_temp > tz->temperature && trip_temp < *high)
+			*high = trip_temp;
 	}
+}
+
+void thermal_zone_set_trips(struct thermal_zone_device *tz)
+{
+	int low, high;
+	int ret;
+
+	mutex_lock(&tz->lock);
+
+	if (!tz->ops->set_trips || !tz->ops->get_trip_hyst)
+		goto exit;
+
+	thermal_zone_get_trip(tz, &low, &high);
 
 	/* No need to change trip points */
 	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 09e1669a4919..000ae6a97678 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -443,6 +443,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
 				       struct thermal_cooling_device *);
 void thermal_zone_device_update(struct thermal_zone_device *,
 				enum thermal_notify_event);
+void thermal_zone_get_trip(struct thermal_zone_device *tz, int *low, int *high);
 void thermal_zone_set_trips(struct thermal_zone_device *);
 
 struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
@@ -496,6 +497,9 @@ static inline int thermal_zone_unbind_cooling_device(
 static inline void thermal_zone_device_update(struct thermal_zone_device *tz,
 					      enum thermal_notify_event event)
 { }
+static inline void thermal_zone_get_trip(struct thermal_zone_device *tz,
+					 int *low, int *high)
+{ }
 static inline void thermal_zone_set_trips(struct thermal_zone_device *tz)
 { }
 static inline struct thermal_cooling_device *
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH RFC 4/4] drivers: of-thermal: notify framework when sensor is tripped
  2018-05-08 17:48 [PATCH RFC 0/4] drivers/thermal: support for multiple TZ for sensor Lina Iyer
                   ` (2 preceding siblings ...)
  2018-05-08 17:48 ` [PATCH RFC 3/4] drivers: of-thermal: aggregate sensor trips across thermal zones Lina Iyer
@ 2018-05-08 17:48 ` Lina Iyer
  3 siblings, 0 replies; 5+ messages in thread
From: Lina Iyer @ 2018-05-08 17:48 UTC (permalink / raw)
  To: edubezval, rui.zhang
  Cc: linux-pm, linux-kernel, linux-arm-msm, daniel.lezcano,
	amit.kucheria, Lina Iyer

Notify all related thermal zones when the sensor reports a thermal trip.

Signed-off-by: Lina Iyer <ilina@codeaurora.org>
---
 drivers/thermal/of-thermal.c | 83 ++++++++++++++++++++++++++++++++++--
 include/linux/thermal.h      |  4 ++
 2 files changed, 84 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 6fb2eeb5b6cf..9b42bfed78bf 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -41,12 +41,18 @@ struct __thermal_bind_params {
  * @ops: sensor driver ops
  * @tz_list: list of thermal zones for this sensor
  * @lock: lock sensor during operations
+ * @low_trip: sensor's low trip temp
+ * @high_trip: sensor's high trip temp
+ * @low_tz: the thermal zone whose low trip is used as @low_trip
+ * @high_tz: the thermal zone whose high trip is used as @high_trip
  */
 struct thermal_sensor {
 	void *sensor_data;
 	const struct thermal_zone_of_device_ops *ops;
 	struct list_head tz_list;
 	struct mutex lock;
+	int low_trip, high_trip;
+	struct thermal_zone_device *low_tz, *high_tz;
 };
 
 /**
@@ -102,18 +108,26 @@ static void __of_thermal_agg_trip(struct thermal_sensor *sensor,
 	int low, high;
 	int max_lo = INT_MIN;
 	int min_hi = INT_MAX;
-	struct thermal_zone_device *tz;
+	struct thermal_zone_device *tz, *lo_tz = NULL, *hi_tz = NULL;
 
 	list_for_each_entry(tz, &sensor->tz_list, sensor_tzd) {
 		thermal_zone_get_trip(tz, &low, &high);
-		if (low > max_lo)
+		if (low > max_lo) {
 			max_lo = low;
-		if (high < min_hi)
+			lo_tz = tz;
+		}
+		if (high < min_hi) {
 			min_hi = high;
+			hi_tz = tz;
+		}
 	}
 
 	*floor = max_lo;
 	*ceil = min_hi;
+	sensor->low_trip = max_lo;
+	sensor->high_trip = min_hi;
+	sensor->low_tz = lo_tz;
+	sensor->high_tz = hi_tz;
 }
 
 static int of_thermal_set_trips(struct thermal_zone_device *tz,
@@ -427,6 +441,69 @@ static struct thermal_zone_device_ops of_thermal_ops = {
 
 /***   sensor API   ***/
 
+static void thermal_zone_of_get_trip(struct thermal_zone_device *tz,
+				     int temp, int *low_trip, int *hi_trip)
+{
+	struct __thermal_zone *data = tz->devdata;
+	int low = INT_MIN;
+	int hi = INT_MAX;
+	int i;
+
+	for (i = 0; i < data->ntrips; i++) {
+		int trip_temp = data->trips[i].temperature;
+
+		if (trip_temp < temp && trip_temp > low)
+			*low_trip = i;
+		if (trip_temp > temp && trip_temp < hi)
+			*hi_trip = i;
+	}
+}
+
+/**
+ * thermal_zone_of_sensor_notify - notify framework of a trip
+ * @tzd: the thermal zone device
+ *
+ * Sensor drivers may use this API to notify the thermal framework that the
+ * temperature has crossed the trip threshold. This function is akin to
+ * thermal_notify_framework() call, but is expected to be called by a sensor
+ * that registered itself with the framework using the
+ * thermal_zone_of_add_sensor() function.
+ */
+void thermal_zone_of_sensor_notify(struct thermal_zone_device *tzd)
+{
+	struct __thermal_zone *tz = tzd->devdata;
+	struct thermal_sensor *sensor = tz->sensor;
+	int temp, low_trip, hi_trip, *trip;
+	struct thermal_zone_device *trip_tz = NULL;
+
+	if (!tz->sensor)
+		return;
+
+	if (of_thermal_get_temp(tzd, &temp))
+		return;
+
+	mutex_lock(&sensor->lock);
+	if (tzd->temperature < sensor->low_trip && sensor->low_tz) {
+		trip_tz = sensor->low_tz;
+		trip = &low_trip;
+	}
+	if (tzd->temperature > sensor->high_trip && sensor->high_tz) {
+		trip_tz = sensor->high_tz;
+		trip = &hi_trip;
+	}
+
+	if (trip_tz)
+		thermal_zone_of_get_trip(trip_tz, temp, &low_trip, &hi_trip);
+
+	mutex_unlock(&sensor->lock);
+
+	if (!trip_tz)
+		return;
+
+	thermal_notify_framework(trip_tz, *trip);
+}
+EXPORT_SYMBOL(thermal_zone_of_sensor_notify);
+
 static struct thermal_zone_device *
 thermal_zone_of_add_sensor(struct device_node *zone,
 			   struct device_node *sensor_np,
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 000ae6a97678..603bf8065d7d 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -388,6 +388,7 @@ struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
 		const struct thermal_zone_of_device_ops *ops);
 void devm_thermal_zone_of_sensor_unregister(struct device *dev,
 					    struct thermal_zone_device *tz);
+void thermal_zone_of_sensor_notify(struct thermal_zone_device *tzd);
 #else
 static inline struct thermal_zone_device *
 thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
@@ -415,6 +416,9 @@ void devm_thermal_zone_of_sensor_unregister(struct device *dev,
 {
 }
 
+static inline
+void thermal_zone_of_sensor_notify(struct thermal_zone_device *tzd)
+{ }
 #endif
 
 #if IS_ENABLED(CONFIG_THERMAL)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

end of thread, other threads:[~2018-05-08 17:49 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-08 17:48 [PATCH RFC 0/4] drivers/thermal: support for multiple TZ for sensor Lina Iyer
2018-05-08 17:48 ` [PATCH RFC 1/4] drivers: of-thermal: abstract sensor related information Lina Iyer
2018-05-08 17:48 ` [PATCH RFC 2/4] drivers: of-thermal: allow multiple thermal zones for a sensor Lina Iyer
2018-05-08 17:48 ` [PATCH RFC 3/4] drivers: of-thermal: aggregate sensor trips across thermal zones Lina Iyer
2018-05-08 17:48 ` [PATCH RFC 4/4] drivers: of-thermal: notify framework when sensor is tripped Lina Iyer

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).