mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-12 07:37:31 -04:00
Merge "drivers: thermal: Add support to change thermal zone configuration"
This commit is contained in:
commit
60cf653523
5 changed files with 418 additions and 0 deletions
|
|
@ -27,6 +27,9 @@ thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o
|
|||
# devfreq cooling
|
||||
thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
|
||||
|
||||
# debugfs support
|
||||
thermal_sys-$(CONFIG_QTI_THERMAL) += thermal_debugfs.o
|
||||
|
||||
# platform thermal drivers
|
||||
obj-y += broadcom/
|
||||
obj-$(CONFIG_THERMAL_MMIO) += thermal_mmio.o
|
||||
|
|
|
|||
|
|
@ -466,8 +466,19 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
|
|||
mutex_lock(&tz->lock);
|
||||
|
||||
if (mode == THERMAL_DEVICE_ENABLED) {
|
||||
#ifdef CONFIG_QTI_THERMAL
|
||||
if (!tz->polling_delay)
|
||||
tz->polling_delay = data->polling_delay;
|
||||
else
|
||||
data->polling_delay = tz->polling_delay;
|
||||
if (!tz->passive_delay)
|
||||
tz->passive_delay = data->passive_delay;
|
||||
else
|
||||
data->passive_delay = tz->passive_delay;
|
||||
#else
|
||||
tz->polling_delay = data->polling_delay;
|
||||
tz->passive_delay = data->passive_delay;
|
||||
#endif
|
||||
} else {
|
||||
tz->polling_delay = 0;
|
||||
tz->passive_delay = 0;
|
||||
|
|
|
|||
|
|
@ -1799,6 +1799,7 @@ static int __init thermal_init(void)
|
|||
if (result)
|
||||
pr_warn("Thermal: Can not register suspend notifier, return %d\n",
|
||||
result);
|
||||
thermal_debug_init();
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -1824,6 +1825,7 @@ static void thermal_exit(void)
|
|||
destroy_workqueue(thermal_passive_wq);
|
||||
genetlink_exit();
|
||||
class_unregister(&thermal_class);
|
||||
thermal_debug_exit();
|
||||
thermal_unregister_governors();
|
||||
ida_destroy(&thermal_tz_ida);
|
||||
ida_destroy(&thermal_cdev_ida);
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ void of_thermal_handle_trip(struct device *dev,
|
|||
void of_thermal_handle_trip_temp(struct device *dev,
|
||||
struct thermal_zone_device *tz,
|
||||
int trip_temp);
|
||||
int thermal_debug_init(void);
|
||||
void thermal_debug_exit(void);
|
||||
#else
|
||||
static inline int of_thermal_aggregate_trip(struct device *dev,
|
||||
struct thermal_zone_device *tz,
|
||||
|
|
@ -141,6 +143,12 @@ static inline
|
|||
void of_thermal_handle_trip_temp(struct device *dev,
|
||||
struct thermal_zone_device *tz, int trip_temp)
|
||||
{ }
|
||||
static inline int thermal_debug_init(void)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline void thermal_debug_exit(void)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
#endif /* __THERMAL_CORE_H__ */
|
||||
|
|
|
|||
394
drivers/thermal/thermal_debugfs.c
Normal file
394
drivers/thermal/thermal_debugfs.c
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "thermal_core.h"
|
||||
|
||||
#define SPACE_DELIMITER " \t"
|
||||
|
||||
static struct dentry *thermal_debugfs_parent;
|
||||
static struct dentry *thermal_debugfs_config;
|
||||
|
||||
static int fetch_cdev(struct thermal_zone_device *tz, char *dev_token,
|
||||
char *upper_lim_token, char *lower_lim_token, int trip)
|
||||
{
|
||||
unsigned long upper_limit, lower_limit;
|
||||
char cdev_name[THERMAL_NAME_LENGTH] = "";
|
||||
char limit_str[THERMAL_NAME_LENGTH] = "";
|
||||
struct thermal_instance *instance;
|
||||
bool match_found = false;
|
||||
|
||||
dev_token = strim(dev_token);
|
||||
if (sscanf(dev_token, "%20[^ +\n\t]", cdev_name) != 1)
|
||||
return -EINVAL;
|
||||
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
|
||||
if (!instance->cdev || instance->trip != trip)
|
||||
continue;
|
||||
|
||||
if (strcmp(instance->cdev->type, cdev_name))
|
||||
continue;
|
||||
match_found = true;
|
||||
break;
|
||||
}
|
||||
if (!match_found)
|
||||
return -ENODEV;
|
||||
if (upper_lim_token) {
|
||||
if (sscanf(upper_lim_token, "%20[^ +\n\t]", limit_str) != 1)
|
||||
return -EINVAL;
|
||||
if (kstrtoul(limit_str, 0, &upper_limit))
|
||||
return -EINVAL;
|
||||
instance->upper = upper_limit;
|
||||
}
|
||||
if (lower_lim_token) {
|
||||
if (sscanf(lower_lim_token, "%20[^ +\n\t]", limit_str) != 1)
|
||||
return -EINVAL;
|
||||
if (kstrtoul(limit_str, 0, &lower_limit))
|
||||
return -EINVAL;
|
||||
instance->lower = lower_limit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fetch_and_update_cdev(struct thermal_zone_device *tz, int trip,
|
||||
char **dev_buf, char *dev_buf_end,
|
||||
char **up_buf, char *up_buf_end,
|
||||
char **low_buf, char *low_buf_end)
|
||||
{
|
||||
int ret;
|
||||
char *dev_token, *upper_lim_token, *lower_lim_token, *dev1_token;
|
||||
|
||||
dev_token = strsep(dev_buf, SPACE_DELIMITER);
|
||||
if (*up_buf) {
|
||||
upper_lim_token = strsep(up_buf, SPACE_DELIMITER);
|
||||
upper_lim_token = strnchr(*up_buf, up_buf_end - *up_buf,
|
||||
' ');
|
||||
if (upper_lim_token && upper_lim_token < up_buf_end)
|
||||
up_buf_end = upper_lim_token;
|
||||
}
|
||||
if (*low_buf) {
|
||||
lower_lim_token = strsep(low_buf, SPACE_DELIMITER);
|
||||
lower_lim_token = strnchr(*low_buf, low_buf_end - *low_buf,
|
||||
' ');
|
||||
if (lower_lim_token && lower_lim_token < low_buf_end)
|
||||
low_buf_end = lower_lim_token;
|
||||
}
|
||||
if (dev_token && *dev_buf < dev_buf_end) {
|
||||
do {
|
||||
ret = fetch_cdev(tz, *dev_buf, *up_buf,
|
||||
*low_buf, trip);
|
||||
if (ret)
|
||||
return ret;
|
||||
dev1_token = strnchr(*dev_buf, dev_buf_end - *dev_buf,
|
||||
'+');
|
||||
if (!dev1_token || dev1_token >= dev_buf_end)
|
||||
break;
|
||||
dev1_token = strsep(dev_buf, "+");
|
||||
if (*up_buf) {
|
||||
upper_lim_token = strnchr(*up_buf,
|
||||
up_buf_end - *up_buf,
|
||||
'+');
|
||||
if (!upper_lim_token ||
|
||||
upper_lim_token >= up_buf_end)
|
||||
return -EINVAL;
|
||||
upper_lim_token = strsep(up_buf, "+");
|
||||
}
|
||||
if (*low_buf) {
|
||||
lower_lim_token = strnchr(*low_buf,
|
||||
low_buf_end - *low_buf,
|
||||
'+');
|
||||
if (!lower_lim_token ||
|
||||
lower_lim_token >= low_buf_end)
|
||||
return -EINVAL;
|
||||
lower_lim_token = strsep(low_buf, "+");
|
||||
}
|
||||
} while (dev1_token);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fetch_and_update_threshold(struct thermal_zone_device *tz, int trip,
|
||||
char **temp_buf, char *temp_buf_end, bool is_trip)
|
||||
{
|
||||
int ret, trip_temp;
|
||||
char *tripT_token;
|
||||
|
||||
tripT_token = strsep(temp_buf, SPACE_DELIMITER);
|
||||
if (tripT_token && *temp_buf < temp_buf_end) {
|
||||
if (kstrtoint(*temp_buf, 0, &trip_temp))
|
||||
return -EINVAL;
|
||||
if (is_trip)
|
||||
ret = tz->ops->set_trip_temp(tz, trip, trip_temp);
|
||||
else
|
||||
ret = tz->ops->set_trip_hyst(tz, trip, trip_temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_threshold(struct thermal_zone_device *tz, char *buf_ptr,
|
||||
size_t count)
|
||||
{
|
||||
char *trip_buf_end = NULL, *temp_buf_end = NULL, *hyst_buf_end = NULL;
|
||||
char *trip_buf = NULL, *temp_buf = NULL, *hyst_buf = NULL;
|
||||
char *dev_buf_end = NULL, *up_buf_end = NULL, *low_buf_end = NULL;
|
||||
char *dev_buf = NULL, *up_buf = NULL, *low_buf = NULL;
|
||||
char *buf = buf_ptr, *token = NULL;
|
||||
int ret;
|
||||
|
||||
trip_buf = strnstr(buf, "trip", count);
|
||||
trip_buf_end = strnchr(trip_buf, buf_ptr + count - trip_buf, '\n');
|
||||
if (!trip_buf_end)
|
||||
return -EINVAL;
|
||||
|
||||
temp_buf = strnstr(buf, "trip_threshold", count);
|
||||
if (!temp_buf)
|
||||
goto eval_device;
|
||||
if (!tz->ops->set_trip_temp)
|
||||
return -EPERM;
|
||||
|
||||
temp_buf_end = strnchr(temp_buf, buf_ptr + count - temp_buf, '\n');
|
||||
if (!temp_buf_end)
|
||||
return -EINVAL;
|
||||
|
||||
hyst_buf = strnstr(buf, "trip_threshold_clr", count);
|
||||
if (hyst_buf) {
|
||||
if (!tz->ops->set_trip_hyst)
|
||||
return -EPERM;
|
||||
hyst_buf_end = strnchr(hyst_buf,
|
||||
buf_ptr + count - hyst_buf, '\n');
|
||||
if (!hyst_buf_end)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
eval_device:
|
||||
dev_buf = strnstr(buf, "device", count);
|
||||
if (!dev_buf) {
|
||||
if (!temp_buf)
|
||||
return -EINVAL;
|
||||
goto parse_config;
|
||||
}
|
||||
dev_buf_end = strnchr(dev_buf, buf_ptr + count - dev_buf, '\n');
|
||||
if (!dev_buf_end)
|
||||
return -EINVAL;
|
||||
|
||||
up_buf = strnstr(buf, "upper_limit", count);
|
||||
if (!up_buf)
|
||||
return -EINVAL;
|
||||
up_buf_end = strnchr(up_buf, buf_ptr + count - up_buf, '\n');
|
||||
if (!up_buf_end)
|
||||
return -EINVAL;
|
||||
|
||||
low_buf = strnstr(buf, "lower_limit", count);
|
||||
if (!low_buf)
|
||||
return -EINVAL;
|
||||
low_buf_end = strnchr(low_buf, buf_ptr + count - low_buf, '\n');
|
||||
if (!low_buf_end)
|
||||
return -EINVAL;
|
||||
parse_config:
|
||||
*trip_buf_end = '\0';
|
||||
if (temp_buf_end)
|
||||
*temp_buf_end = '\0';
|
||||
if (hyst_buf_end)
|
||||
*hyst_buf_end = '\0';
|
||||
if (dev_buf_end)
|
||||
*dev_buf_end = '\0';
|
||||
if (up_buf_end)
|
||||
*up_buf_end = '\0';
|
||||
if (low_buf_end)
|
||||
*low_buf_end = '\0';
|
||||
token = strnchr(trip_buf, trip_buf_end - trip_buf, ' ');
|
||||
while (token && token < trip_buf_end) {
|
||||
int trip;
|
||||
|
||||
token = strsep((char **)&trip_buf, " ");
|
||||
if (kstrtoint(trip_buf, 0, &trip))
|
||||
return -EINVAL;
|
||||
|
||||
if (temp_buf) {
|
||||
ret = fetch_and_update_threshold(tz, trip, &temp_buf,
|
||||
temp_buf_end, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (hyst_buf) {
|
||||
ret = fetch_and_update_threshold(tz, trip, &hyst_buf,
|
||||
hyst_buf_end, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dev_buf) {
|
||||
ret = fetch_and_update_cdev(tz, trip, &dev_buf,
|
||||
dev_buf_end, &up_buf, up_buf_end,
|
||||
&low_buf, low_buf_end);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
token = strnchr(trip_buf, trip_buf_end - trip_buf, ' ');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_delay(struct thermal_zone_device *tz, char *buf,
|
||||
size_t count, bool is_polling)
|
||||
{
|
||||
int delay = 0;
|
||||
|
||||
if (is_polling) {
|
||||
if (sscanf(buf, "polling_delay %d", &delay) != 1)
|
||||
return -EINVAL;
|
||||
tz->polling_delay = delay;
|
||||
} else {
|
||||
if (sscanf(buf, "passive_polling_delay %d", &delay) != 1)
|
||||
return -EINVAL;
|
||||
tz->passive_delay = delay;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_config(struct thermal_zone_device *tz, char *buf_ptr,
|
||||
size_t buf_ct)
|
||||
{
|
||||
char *buf, *buf_end, *next_buf, *curr_buf;
|
||||
int count, ret = 0;
|
||||
enum thermal_device_mode mode = THERMAL_DEVICE_ENABLED;
|
||||
|
||||
if (tz->ops->get_mode) {
|
||||
ret = tz->ops->get_mode(tz, &mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (tz->ops->set_mode) {
|
||||
ret = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
mutex_lock(&tz->lock);
|
||||
buf = kzalloc(sizeof(char) * (buf_ct + 1), GFP_KERNEL);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto parse_exit;
|
||||
}
|
||||
strlcpy(buf, buf_ptr, (buf_ct + 1));
|
||||
buf_end = buf + buf_ct;
|
||||
if (strnstr(buf, "trip", buf_ct)) {
|
||||
ret = parse_threshold(tz, buf, buf_ct);
|
||||
if (ret)
|
||||
goto parse_exit;
|
||||
}
|
||||
strlcpy(buf, buf_ptr, (buf_ct + 1));
|
||||
curr_buf = next_buf = buf;
|
||||
strsep(&next_buf, "\n");
|
||||
while (curr_buf && curr_buf < buf_end) {
|
||||
if (next_buf)
|
||||
count = next_buf - curr_buf;
|
||||
else
|
||||
count = buf_end - curr_buf + 1;
|
||||
if (strnstr(curr_buf, "passive_polling_delay", count))
|
||||
ret = parse_delay(tz, curr_buf, count, false);
|
||||
else if (strnstr(curr_buf, "polling_delay", count))
|
||||
ret = parse_delay(tz, curr_buf, count, true);
|
||||
|
||||
if (ret)
|
||||
goto parse_exit;
|
||||
|
||||
curr_buf = next_buf;
|
||||
if (next_buf < buf_end)
|
||||
strsep(&next_buf, "\n");
|
||||
else
|
||||
next_buf = NULL;
|
||||
}
|
||||
parse_exit:
|
||||
mutex_unlock(&tz->lock);
|
||||
if (mode == THERMAL_DEVICE_ENABLED && tz->ops->set_mode)
|
||||
tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
|
||||
kfree(buf);
|
||||
return ret ? ret : buf_ct;
|
||||
}
|
||||
|
||||
static ssize_t thermal_dbgfs_config_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct thermal_zone_device *tz = NULL;
|
||||
char *sensor_buf = NULL, sensor_name[THERMAL_NAME_LENGTH] = "", *buf;
|
||||
int ret = -EINVAL;
|
||||
|
||||
buf = kzalloc(sizeof(char) * (count + 1), GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(buf, user_buf, count)) {
|
||||
ret = -EFAULT;
|
||||
goto config_exit;
|
||||
}
|
||||
sensor_buf = strnstr(buf, "sensor", count);
|
||||
if (sensor_buf) {
|
||||
if (sscanf(sensor_buf, "sensor %20[^\n\t ]",
|
||||
sensor_name) != 1) {
|
||||
pr_err("sensor name not found\n");
|
||||
ret = -EINVAL;
|
||||
goto config_exit;
|
||||
}
|
||||
tz = thermal_zone_get_zone_by_name((const char *)sensor_name);
|
||||
if (IS_ERR(tz)) {
|
||||
ret = PTR_ERR(tz);
|
||||
pr_err("No thermal zone for sensor:%s. err:%d\n",
|
||||
sensor_name, ret);
|
||||
goto config_exit;
|
||||
}
|
||||
ret = parse_config(tz, buf, count);
|
||||
}
|
||||
|
||||
config_exit:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations thermal_dbgfs_config_fops = {
|
||||
.write = thermal_dbgfs_config_write,
|
||||
};
|
||||
|
||||
int thermal_debug_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
thermal_debugfs_parent = debugfs_create_dir("thermal", NULL);
|
||||
if (IS_ERR_OR_NULL(thermal_debugfs_parent)) {
|
||||
ret = PTR_ERR(thermal_debugfs_parent);
|
||||
pr_err("Error creating thermal debugfs directory. err:%d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
thermal_debugfs_config = debugfs_create_file("config", 0200,
|
||||
thermal_debugfs_parent, NULL,
|
||||
&thermal_dbgfs_config_fops);
|
||||
if (IS_ERR_OR_NULL(thermal_debugfs_config)) {
|
||||
ret = PTR_ERR(thermal_debugfs_config);
|
||||
pr_err("Error creating thermal config debugfs. err:%d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void thermal_debug_exit(void)
|
||||
{
|
||||
debugfs_remove_recursive(thermal_debugfs_parent);
|
||||
}
|
||||
Loading…
Reference in a new issue