Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f9d4dc1 authored by Ram Chandrasekar's avatar Ram Chandrasekar
Browse files

thermal: Add Support for enabling and disabling tsens trip



Add new API to enable or disable the kernel client's trip
threshold request. The enable or disable trip threshold requests
from different kernel clients and userspace client will
activate/deactivate the corresponding clients threshold request.

Modify thermal sys framework to include only the active
thresholds from clients to determine the current trip
thresholds for tsens.

CRs-Fixed: 561775
Change-Id: I304ac00daa8a0a1a68b60153c29ee6cb5c3507b1
Signed-off-by: default avatarRam Chandrasekar <rkumbako@codeaurora.org>
parent 795c7f2e
Loading
Loading
Loading
Loading
+90 −14
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/regulator/consumer.h>

#define MAX_RAILS 5
#define MAX_THRESHOLD 2

static struct msm_thermal_data msm_thermal_info;
static uint32_t limited_max_freq = UINT_MAX;
@@ -77,8 +78,10 @@ struct cpu_info {
	uint32_t cpu;
	bool offline;
	bool user_offline;
	bool thresh_cleared;
	const char *sensor_type;
	struct sensor_threshold thresh[2];
	uint32_t sensor_id;
	struct sensor_threshold thresh[MAX_THRESHOLD];
};

struct rail {
@@ -624,6 +627,76 @@ static int update_cpu_max_freq(int cpu, uint32_t max_freq)
	return ret;
}

static int set_and_activate_threshold(uint32_t sensor_id,
	struct sensor_threshold *threshold)
{
	int ret = 0;

	ret = sensor_set_trip(sensor_id, threshold);
	if (ret != 0) {
		pr_err("%s: Error in setting trip %d\n",
			KBUILD_MODNAME, threshold->trip);
		goto set_done;
	}

	ret = sensor_activate_trip(sensor_id, threshold, true);
	if (ret != 0) {
		pr_err("%s: Error in enabling trip %d\n",
			KBUILD_MODNAME, threshold->trip);
		goto set_done;
	}

set_done:
	return ret;
}

static int set_threshold(uint32_t sensor_id,
	struct sensor_threshold *threshold)
{
	struct tsens_device tsens_dev;
	int i = 0, ret = 0;
	long temp;

	if ((!threshold) || check_sensor_id(sensor_id)) {
		pr_err("%s: Invalid input\n", KBUILD_MODNAME);
		ret = -EINVAL;
		goto set_threshold_exit;
	}

	tsens_dev.sensor_num = sensor_id;
	ret = tsens_get_temp(&tsens_dev, &temp);
	if (ret) {
		pr_err("%s: Unable to read TSENS sensor %d\n",
			KBUILD_MODNAME, tsens_dev.sensor_num);
		goto set_threshold_exit;
	}
	while (i < MAX_THRESHOLD) {
		switch (threshold[i].trip) {
		case THERMAL_TRIP_CONFIGURABLE_HI:
			if (threshold[i].temp >= temp) {
				ret = set_and_activate_threshold(sensor_id,
					&threshold[i]);
				if (ret)
					goto set_threshold_exit;
			}
			break;
		case THERMAL_TRIP_CONFIGURABLE_LOW:
			if (threshold[i].temp <= temp) {
				ret = set_and_activate_threshold(sensor_id,
					&threshold[i]);
				if (ret)
					goto set_threshold_exit;
			}
			break;
		default:
			break;
		}
		i++;
	}
set_threshold_exit:
	return ret;
}

#ifdef CONFIG_SMP
static void __ref do_core_control(long temp)
{
@@ -677,7 +750,7 @@ static void __ref do_core_control(long temp)
/* Call with core_control_mutex locked */
static int __ref update_offline_cores(int val)
{
	int cpu = 0;
	uint32_t cpu = 0;
	int ret = 0;

	if (!core_control_enabled)
@@ -701,8 +774,7 @@ static int __ref update_offline_cores(int val)
static __ref int do_hotplug(void *data)
{
	int ret = 0;
	int cpu = 0;
	uint32_t mask = 0;
	uint32_t cpu = 0, mask = 0;

	if (!core_control_enabled)
		return -EINVAL;
@@ -714,6 +786,11 @@ static __ref int do_hotplug(void *data)

		mutex_lock(&core_control_mutex);
		for_each_possible_cpu(cpu) {
			if (cpus[cpu].thresh_cleared) {
				set_threshold(cpus[cpu].sensor_id,
					cpus[cpu].thresh);
				cpus[cpu].thresh_cleared = false;
			}
			if (cpus[cpu].offline || cpus[cpu].user_offline)
				mask |= BIT(cpu);
		}
@@ -980,9 +1057,10 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data)
	default:
		break;
	}
	if (hotplug_task)
	if (hotplug_task) {
		cpu_node->thresh_cleared = true;
		complete(&hotplug_notify_complete);
	else
	} else
		pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
	return 0;
}
@@ -997,8 +1075,7 @@ static int hotplug_init_cpu_offlined(void)
	for_each_possible_cpu(cpu) {
		if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
			continue;
		tsens_dev.sensor_num = sensor_get_id(\
				(char *)cpus[cpu].sensor_type);
		tsens_dev.sensor_num = cpus[cpu].sensor_id;
		if (tsens_get_temp(&tsens_dev, &temp)) {
			pr_err("%s: Unable to read TSENS sensor %d\n",
				KBUILD_MODNAME, tsens_dev.sensor_num);
@@ -1031,24 +1108,23 @@ static void hotplug_init(void)
		return;

	for_each_possible_cpu(cpu) {
		cpus[cpu].cpu = (uint32_t)cpu;
		cpus[cpu].thresh_cleared = false;
		cpus[cpu].sensor_id =
			sensor_get_id((char *)cpus[cpu].sensor_type);
		if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
			continue;
		cpus[cpu].cpu = (uint32_t)cpu;
		cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
		cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
		cpus[cpu].thresh[0].notify = hotplug_notify;
		cpus[cpu].thresh[0].data = (void *)&cpus[cpu];
		sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
				&cpus[cpu].thresh[0]);

		cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
				msm_thermal_info.hotplug_temp_hysteresis_degC;
		cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
		cpus[cpu].thresh[1].notify = hotplug_notify;
		cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
		sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
				&cpus[cpu].thresh[1]);

		set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh);
	}
	init_completion(&hotplug_notify_complete);
	hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
+158 −97
Original line number Diff line number Diff line
@@ -156,31 +156,22 @@ int sensor_get_id(char *name)
}
EXPORT_SYMBOL(sensor_get_id);

static long get_min(struct sensor_info *sensor, long temp)
static int __update_sensor_thresholds(struct sensor_info *sensor)
{
	long min = LONG_MIN;
	long max_of_low_thresh = LONG_MIN;
	long min_of_high_thresh = LONG_MAX;
	struct sensor_threshold *pos, *var;
	enum thermal_trip_type type;
	int i, ret = 0;

	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
		if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW)
			if (pos->temp < temp && pos->temp > min)
				min = pos->temp;
	}

	return min;
	if (!sensor->tz->ops->set_trip_temp ||
		!sensor->tz->ops->activate_trip_type ||
		!sensor->tz->ops->get_trip_type ||
		!sensor->tz->ops->get_trip_temp) {
		ret = -ENODEV;
		goto update_done;
	}

static void __update_sensor_thresholds(struct sensor_info *sensor)
{
	long min = LONG_MIN;
	long max = LONG_MAX;
	long max_of_min = LONG_MIN;
	long min_of_max = LONG_MAX;
	struct sensor_threshold *pos, *var;
	enum thermal_trip_type type;
	int i;
	long curr_temp;

	for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
		(sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
		i++) {
@@ -195,60 +186,85 @@ static void __update_sensor_thresholds(struct sensor_info *sensor)
			THERMAL_TRIP_CONFIGURABLE_HI, &sensor->threshold_max);
	}

	sensor->tz->ops->get_temp(sensor->tz, &curr_temp);
	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
		if (!pos->active)
			continue;
		if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) {
			if (pos->temp > max_of_min)
				max_of_min = pos->temp;
			if (pos->temp < curr_temp && pos->temp > min)
				min = pos->temp;
			if (pos->temp > max_of_low_thresh)
				max_of_low_thresh = pos->temp;
		}
		if (pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) {
			if (pos->temp < min_of_max)
				min_of_max = pos->temp;
			if (pos->temp > curr_temp && pos->temp < max)
				max = pos->temp;
			if (pos->temp < min_of_high_thresh)
				min_of_high_thresh = pos->temp;
		}
	}

	pr_debug("sensor %d: min of max: %ld max of min: %ld\n",
			sensor->sensor_id, max_of_min, min_of_max);
	pr_debug("sensor %d: Thresholds: max of low: %ld min of high: %ld\n",
			sensor->sensor_id, max_of_low_thresh,
			min_of_high_thresh);

	/* If we haven't found a max and min bounding the curr_temp,
	 * use the min of max and max of min instead.
	 */
	if (max == LONG_MAX)
		max = min_of_max;
	if (min == LONG_MIN) {
		min = get_min(sensor, max);
		if (min == LONG_MIN)
			min = max_of_min;
	if ((min_of_high_thresh != sensor->threshold_max) &&
		(min_of_high_thresh != LONG_MAX)) {
		ret = sensor->tz->ops->set_trip_temp(sensor->tz,
			sensor->max_idx, min_of_high_thresh);
		if (ret) {
			pr_err("sensor %d: Unable to set high threshold %d",
					sensor->sensor_id, ret);
			goto update_done;
		}
		sensor->threshold_max = min_of_high_thresh;
	}
	ret = sensor->tz->ops->activate_trip_type(sensor->tz,
		sensor->max_idx,
		(min_of_high_thresh == LONG_MAX) ?
		THERMAL_TRIP_ACTIVATION_DISABLED :
		THERMAL_TRIP_ACTIVATION_ENABLED);
	if (ret) {
		pr_err("sensor %d: Unable to activate high threshold %d",
			sensor->sensor_id, ret);
		goto update_done;
	}

	if (sensor->tz->ops->set_trip_temp) {
		if (max != sensor->threshold_max) {
			sensor->tz->ops->set_trip_temp(sensor->tz,
				sensor->max_idx, max);
			sensor->threshold_max = max;
	if ((max_of_low_thresh != sensor->threshold_min) &&
		(max_of_low_thresh != LONG_MIN)) {
		ret = sensor->tz->ops->set_trip_temp(sensor->tz,
			sensor->min_idx, max_of_low_thresh);
		if (ret) {
			pr_err("sensor %d: Unable to set low threshold %d",
				sensor->sensor_id, ret);
			goto update_done;
		}
		if (min != sensor->threshold_min) {
			sensor->tz->ops->set_trip_temp(sensor->tz,
				sensor->min_idx, min);
			sensor->threshold_min = min;
		sensor->threshold_min = max_of_low_thresh;
	}
	ret = sensor->tz->ops->activate_trip_type(sensor->tz,
		sensor->min_idx,
		(max_of_low_thresh == LONG_MIN) ?
		THERMAL_TRIP_ACTIVATION_DISABLED :
		THERMAL_TRIP_ACTIVATION_ENABLED);
	if (ret) {
		pr_err("sensor %d: Unable to activate low threshold %d",
			sensor->sensor_id, ret);
		goto update_done;
	}

	pr_debug("sensor %d: curr_temp: %ld min: %ld max: %ld\n",
		sensor->sensor_id, curr_temp,
	pr_debug("sensor %d: low: %ld high: %ld\n",
		sensor->sensor_id,
		sensor->threshold_min, sensor->threshold_max);

update_done:
	return ret;
}

static void sensor_update_work(struct work_struct *work)
{
	struct sensor_info *sensor = container_of(work, struct sensor_info,
						work);
	int ret = 0;
	mutex_lock(&sensor->lock);
	__update_sensor_thresholds(sensor);
	ret = __update_sensor_thresholds(sensor);
	if (ret)
		pr_err("sensor %d: Error %d setting threshold\n",
			sensor->sensor_id, ret);
	mutex_unlock(&sensor->lock);
}

@@ -269,7 +285,7 @@ int thermal_sensor_trip(struct thermal_zone_device *tz,
		return 0;

	list_for_each_entry_safe(pos, var, &tz->sensor.threshold_list, list) {
		if (pos->trip != trip)
		if ((pos->trip != trip) || (!pos->active))
			continue;
		if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
			(pos->temp <= tz->sensor.threshold_min) &&
@@ -277,6 +293,7 @@ int thermal_sensor_trip(struct thermal_zone_device *tz,
			((trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
				(pos->temp >= tz->sensor.threshold_max) &&
				(pos->temp <= temp))) {
			pos->active = 0;
			pos->notify(trip, temp, pos->data);
		}
	}
@@ -287,6 +304,29 @@ int thermal_sensor_trip(struct thermal_zone_device *tz,
}
EXPORT_SYMBOL(thermal_sensor_trip);

int sensor_activate_trip(uint32_t sensor_id,
	struct sensor_threshold *threshold, bool enable)
{
	struct sensor_info *sensor = get_sensor(sensor_id);
	int ret = 0;

	if (!sensor || !threshold) {
		pr_err("%s: uninitialized data\n",
			KBUILD_MODNAME);
		ret = -ENODEV;
		goto activate_trip_exit;
	}

	mutex_lock(&sensor->lock);
	threshold->active = (enable) ? 1 : 0;
	ret = __update_sensor_thresholds(sensor);
	mutex_unlock(&sensor->lock);

activate_trip_exit:
	return ret;
}
EXPORT_SYMBOL(sensor_activate_trip);

int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
{
	struct sensor_threshold *pos, *var;
@@ -308,8 +348,8 @@ int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
		INIT_LIST_HEAD(&threshold->list);
		list_add(&threshold->list, &sensor->threshold_list);
	}
	threshold->active = 0; /* Do not allow active threshold right away */

	__update_sensor_thresholds(sensor);
	mutex_unlock(&sensor->lock);

	return 0;
@@ -321,6 +361,7 @@ int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
{
	struct sensor_threshold *pos, *var;
	struct sensor_info *sensor = get_sensor(sensor_id);
	int ret = 0;

	if (!sensor)
		return -ENODEV;
@@ -328,15 +369,16 @@ int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
	mutex_lock(&sensor->lock);
	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
		if (pos == threshold) {
			pos->active = 0;
			list_del(&pos->list);
			break;
		}
	}

	__update_sensor_thresholds(sensor);
	ret = __update_sensor_thresholds(sensor);
	mutex_unlock(&sensor->lock);

	return 0;
	return ret;
}
EXPORT_SYMBOL(sensor_cancel_trip);

@@ -350,36 +392,36 @@ static int tz_notify_trip(enum thermal_trip_type type, int temp, void *data)
	return 0;
}

static void get_trip_threshold(struct thermal_zone_device *tz, int trip,
	struct sensor_threshold **threshold)
{
	enum thermal_trip_type type;

	tz->ops->get_trip_type(tz, trip, &type);

	if (type == THERMAL_TRIP_CONFIGURABLE_HI)
		*threshold = &tz->tz_threshold[0];
	else if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
		*threshold = &tz->tz_threshold[1];
	else
		*threshold = NULL;
}

int sensor_set_trip_temp(struct thermal_zone_device *tz,
		int trip, long temp)
{
	int ret = 0;
	enum thermal_trip_type type;
	struct sensor_threshold *threshold = NULL;

	if (!tz->ops->get_trip_type)
		return -EPERM;

	tz->ops->get_trip_type(tz, trip, &type);
	switch (type) {
	case THERMAL_TRIP_CONFIGURABLE_HI:
		tz->tz_threshold[0].temp = temp;
		tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
		tz->tz_threshold[0].notify = tz_notify_trip;
		tz->tz_threshold[0].data = tz;
		ret = sensor_set_trip(tz->sensor.sensor_id,
					&tz->tz_threshold[0]);
		break;
	case THERMAL_TRIP_CONFIGURABLE_LOW:
		tz->tz_threshold[1].temp = temp;
		tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
		tz->tz_threshold[1].notify = tz_notify_trip;
		tz->tz_threshold[1].data = tz;
		ret = sensor_set_trip(tz->sensor.sensor_id,
					&tz->tz_threshold[1]);
		break;
	default:
	get_trip_threshold(tz, trip, &threshold);
	if (threshold) {
		threshold->temp = temp;
		ret = sensor_set_trip(tz->sensor.sensor_id, threshold);
	} else {
		ret = tz->ops->set_trip_temp(tz, trip, temp);
		break;
	}

	return ret;
@@ -400,10 +442,12 @@ int sensor_init(struct thermal_zone_device *tz)
	INIT_LIST_HEAD(&sensor->threshold_list);
	INIT_LIST_HEAD(&tz->tz_threshold[0].list);
	INIT_LIST_HEAD(&tz->tz_threshold[1].list);
	tz->tz_threshold[0].notify = NULL;
	tz->tz_threshold[0].data = NULL;
	tz->tz_threshold[1].notify = NULL;
	tz->tz_threshold[1].data = NULL;
	tz->tz_threshold[0].notify = tz_notify_trip;
	tz->tz_threshold[0].data = tz;
	tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
	tz->tz_threshold[1].notify = tz_notify_trip;
	tz->tz_threshold[1].data = tz;
	tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
	list_add(&sensor->sensor_list, &sensor_info_list);
	INIT_WORK(&sensor->work, sensor_update_work);

@@ -860,23 +904,40 @@ trip_point_type_activate(struct device *dev, struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct thermal_zone_device *tz = to_thermal_zone(dev);
	int trip, result;
	int trip, result = 0;
	bool activate;
	struct sensor_threshold *threshold = NULL;

	if (!tz->ops->activate_trip_type)
		return -EPERM;
	if (!tz->ops->get_trip_type ||
		!tz->ops->activate_trip_type) {
		result = -EPERM;
		goto trip_activate_exit;
	}

	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
		return -EINVAL;
	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) {
		result = -EINVAL;
		goto trip_activate_exit;
	}

	if (!strncmp(buf, "enabled", sizeof("enabled")))
		result = tz->ops->activate_trip_type(tz, trip,
					THERMAL_TRIP_ACTIVATION_ENABLED);
	else if (!strncmp(buf, "disabled", sizeof("disabled")))
	if (!strcmp(buf, "enabled")) {
		activate = true;
	} else if (!strcmp(buf, "disabled")) {
		activate = false;
	} else {
		result = -EINVAL;
		goto trip_activate_exit;
	}

	get_trip_threshold(tz, trip, &threshold);
	if (threshold)
		result = sensor_activate_trip(tz->sensor.sensor_id,
			threshold, activate);
	else
		result = tz->ops->activate_trip_type(tz, trip,
			activate ? THERMAL_TRIP_ACTIVATION_ENABLED :
			THERMAL_TRIP_ACTIVATION_DISABLED);
	else
		result = -EINVAL;

trip_activate_exit:
	if (result)
		return result;

+3 −0
Original line number Diff line number Diff line
@@ -171,6 +171,7 @@ struct sensor_threshold {
	enum thermal_trip_type trip;
	int (*notify)(enum thermal_trip_type type, int temp, void *data);
	void *data;
	uint8_t active;
	struct list_head list;
};

@@ -284,6 +285,8 @@ void thermal_notify_framework(struct thermal_zone_device *, int);
int sensor_get_id(char *name);
int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
int sensor_activate_trip(uint32_t sensor_id, struct sensor_threshold *threshold,
		bool enable);
int thermal_sensor_trip(struct thermal_zone_device *tz,
		enum thermal_trip_type trip, long temp);