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

Commit bd155705 authored by Ram Chandrasekar's avatar Ram Chandrasekar
Browse files

drivers: thermal: Add support to handle cooling device floor



Some silicons operating at low temperatures outside of its operating
temperature range need to increase the supply voltage for timing
closure. In order to achieve this, the cooling device should be able to
place an operating floor mitigation on a cooling device.

Add new optional callbacks in the framework for the cooling device to
register if they support placing a floor mitigation. These two callbacks
will be used by thermal core framework to set and get the current floor
request. Also add support in thermal sysfs to set and get the floor request
from userspace. Thermal framework aggregates the floor requests from
multiple thermal zones and then notifies the cooling device.

Change-Id: I4a01e46c8e576a41e1cb5c1f8e479b1a68fc8003
Signed-off-by: default avatarRam Chandrasekar <rkumbako@codeaurora.org>
parent 5ab1c08e
Loading
Loading
Loading
Loading
+61 −4
Original line number Diff line number Diff line
@@ -1199,6 +1199,25 @@ thermal_cooling_device_max_state_show(struct device *dev,
	return sprintf(buf, "%ld\n", state);
}

static ssize_t
thermal_cooling_device_min_state_show(struct device *dev,
				      struct device_attribute *attr, char *buf)
{
	struct thermal_cooling_device *cdev = to_cooling_device(dev);
	unsigned long state;
	int ret;

	if (cdev->ops->get_min_state)
		ret = cdev->ops->get_min_state(cdev, &state);
	else
		ret = -EPERM;

	if (ret)
		return ret;

	return snprintf(buf, PAGE_SIZE, "%lu\n", state);
}

static ssize_t
thermal_cooling_device_cur_state_show(struct device *dev,
				      struct device_attribute *attr, char *buf)
@@ -1235,6 +1254,30 @@ thermal_cooling_device_cur_state_store(struct device *dev,
	return count;
}

static ssize_t
thermal_cooling_device_min_state_store(struct device *dev,
				       struct device_attribute *attr,
				       const char *buf, size_t count)
{
	struct thermal_cooling_device *cdev = to_cooling_device(dev);
	long state;
	int ret = 0;

	ret = sscanf(buf, "%ld\n", &state);
	if (ret <= 0)
		return (ret < 0) ? ret : -EINVAL;

	if ((long)state < 0)
		return -EINVAL;

	cdev->sysfs_min_state_req = state;

	cdev->updated = false;
	thermal_cdev_update(cdev);

	return count;
}

static struct device_attribute dev_attr_cdev_type =
__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
static DEVICE_ATTR(max_state, 0444,
@@ -1242,6 +1285,9 @@ static DEVICE_ATTR(max_state, 0444,
static DEVICE_ATTR(cur_state, 0644,
		   thermal_cooling_device_cur_state_show,
		   thermal_cooling_device_cur_state_store);
static DEVICE_ATTR(min_state, 0644,
		   thermal_cooling_device_min_state_show,
		   thermal_cooling_device_min_state_store);

static ssize_t
thermal_cooling_device_trip_point_show(struct device *dev,
@@ -1262,6 +1308,7 @@ static struct attribute *cooling_device_attrs[] = {
	&dev_attr_cdev_type.attr,
	&dev_attr_max_state.attr,
	&dev_attr_cur_state.attr,
	&dev_attr_min_state.attr,
	NULL,
};

@@ -1556,6 +1603,7 @@ __thermal_cooling_device_register(struct device_node *np,
	cdev->device.groups = cooling_device_attr_groups;
	cdev->devdata = devdata;
	cdev->sysfs_cur_state_req = 0;
	cdev->sysfs_min_state_req = ULONG_MAX;
	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
	result = device_register(&cdev->device);
	if (result) {
@@ -1690,7 +1738,7 @@ EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
void thermal_cdev_update(struct thermal_cooling_device *cdev)
{
	struct thermal_instance *instance;
	unsigned long current_target = 0;
	unsigned long current_target = 0, min_target = ULONG_MAX;

	mutex_lock(&cdev->lock);
	/* cooling device is updated*/
@@ -1701,19 +1749,28 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)

	/* Make sure cdev enters the deepest cooling state */
	current_target = cdev->sysfs_cur_state_req;
	min_target = cdev->sysfs_min_state_req;
	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
		dev_dbg(&cdev->device, "zone%d->target=%lu\n",
				instance->tz->id, instance->target);
		if (instance->target == THERMAL_NO_TARGET)
			continue;
		if (instance->tz->governor->min_state_throttle) {
			if (instance->target < min_target)
				min_target = instance->target;
		} else {
			if (instance->target > current_target)
				current_target = instance->target;
		}
	}
	cdev->ops->set_cur_state(cdev, current_target);
	if (cdev->ops->set_min_state)
		cdev->ops->set_min_state(cdev, min_target);
	cdev->updated = true;
	mutex_unlock(&cdev->lock);
	trace_cdev_update(cdev, current_target);
	dev_dbg(&cdev->device, "set to state %lu\n", current_target);
	dev_dbg(&cdev->device, "set to state %lu min state %lu\n",
				current_target, min_target);
}
EXPORT_SYMBOL(thermal_cdev_update);

+3 −0
Original line number Diff line number Diff line
@@ -142,6 +142,8 @@ struct thermal_cooling_device_ops {
	int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
	int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
	int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
	int (*set_min_state)(struct thermal_cooling_device *, unsigned long);
	int (*get_min_state)(struct thermal_cooling_device *, unsigned long *);
	int (*get_requested_power)(struct thermal_cooling_device *,
				   struct thermal_zone_device *, u32 *);
	int (*state2power)(struct thermal_cooling_device *,
@@ -262,6 +264,7 @@ struct thermal_governor {
	void (*unbind_from_tz)(struct thermal_zone_device *tz);
	int (*throttle)(struct thermal_zone_device *tz, int trip);
	struct list_head	governor_list;
	int min_state_throttle;
};

/* Structure that holds binding parameters for a zone */