driver: thermal: userspace_cdev: Add a snapshot of userspace cooling driver

Add a snapshot of qti userspace cooling driver from msm-5.10 as
of commit 90be510a996d ("drivers: userspace_cdev: Add new userspace
cooling device").

Updates:
    - Change GPL v2 license to GPL

Change-Id: I57e07b76bf12a587a167bc4220b45c0d7fd29e8a
Signed-off-by: Manaf Meethalavalappu Pallikunhi <quic_manafm@quicinc.com>
Signed-off-by: Rashid Zafar <quic_rzafar@quicinc.com>
This commit is contained in:
Rashid Zafar 2022-11-04 15:43:52 -07:00
parent 83cf3de091
commit 9408ecee82
3 changed files with 198 additions and 0 deletions

View File

@ -131,3 +131,12 @@ config QTI_DDR_COOLING_DEVICE
to meet the performance requirement under thermally constrained
conditions.
config QTI_USERSPACE_CDEV
tristate "QTI Userspace cooling device"
depends on THERMAL_OF
help
This enables the QTI userspace cooling device, which will help
send the mitigation notification via thermal framework netlink
socket, so that userspace cooling device can perform a mitigation
action.

View File

@ -20,3 +20,4 @@ qti_qmi_sensor_v2-y += thermal_sensor_service_v02.o qmi_sensors_v2.o
obj-$(CONFIG_QTI_CPU_VOLTAGE_COOLING_DEVICE) += cpu_voltage_cooling.o
obj-$(CONFIG_QTI_CPU_HOTPLUG_COOLING_DEVICE) += cpu_hotplug.o
obj-$(CONFIG_QTI_DDR_COOLING_DEVICE) += ddr_cdev.o
obj-$(CONFIG_QTI_USERSPACE_CDEV) += qti_userspace_cdev.o

View File

@ -0,0 +1,188 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/thermal.h>
#define USERSPACE_CDEV_DRIVER "userspace-cdev"
struct userspace_cdev {
struct device_node *np;
char cdev_name[THERMAL_NAME_LENGTH];
struct thermal_cooling_device *cdev;
unsigned int cur_level;
unsigned int max_level;
};
static struct userspace_cdev *cdev_instances;
static int inst_cnt;
static int userspace_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct userspace_cdev *usr_cdev = cdev->devdata;
if (!usr_cdev)
return -EINVAL;
*state = usr_cdev->max_level;
return 0;
}
static int userspace_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct userspace_cdev *usr_cdev = cdev->devdata;
if (!usr_cdev)
return -EINVAL;
*state = usr_cdev->cur_level;
return 0;
}
static int userspace_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct userspace_cdev *usr_cdev = cdev->devdata;
if (!usr_cdev)
return -EINVAL;
if (state > usr_cdev->max_level)
return -EINVAL;
if (usr_cdev->cur_level == state)
return 0;
usr_cdev->cur_level = state;
return 0;
}
static struct thermal_cooling_device_ops userspace_cdev_ops = {
.get_max_state = userspace_get_max_state,
.get_cur_state = userspace_get_cur_state,
.set_cur_state = userspace_set_cur_state,
};
static void userspace_cdev_cleanup(void)
{
int idx = 0;
struct userspace_cdev *usr_cdev = cdev_instances;
for (; idx < inst_cnt; idx++) {
if (usr_cdev[idx].cdev)
thermal_cooling_device_unregister(
usr_cdev[idx].cdev);
usr_cdev[idx].cdev = NULL;
}
inst_cnt = 0;
}
static int userspace_device_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret = 0, idx = 0, subsys_cnt = 0;
struct device_node *np = dev->of_node, *subsys_np = NULL;
subsys_cnt = of_get_available_child_count(np);
if (!subsys_cnt) {
dev_err(dev, "No child node to process\n");
return -EFAULT;
}
cdev_instances = devm_kcalloc(dev, subsys_cnt, sizeof(*cdev_instances),
GFP_KERNEL);
if (!cdev_instances)
return -ENOMEM;
inst_cnt = subsys_cnt;
for_each_available_child_of_node(np, subsys_np) {
if (idx >= subsys_cnt) {
of_node_put(subsys_np);
break;
}
ret = of_property_read_u32(subsys_np, "qcom,max-level",
&cdev_instances[idx].max_level);
if (ret) {
dev_err(dev, "error reading qcom,max-level. ret:%d\n",
ret);
goto probe_error;
}
cdev_instances[idx].np = subsys_np;
strscpy(cdev_instances[idx].cdev_name, subsys_np->name,
THERMAL_NAME_LENGTH);
cdev_instances[idx].cdev = thermal_of_cooling_device_register(
subsys_np,
cdev_instances[idx].cdev_name,
&cdev_instances[idx],
&userspace_cdev_ops);
if (IS_ERR(cdev_instances[idx].cdev)) {
dev_err(dev, "Error registering cdev:%s err:%d\n",
cdev_instances[idx].cdev_name,
PTR_ERR(cdev_instances[idx].cdev));
cdev_instances[idx].cdev = NULL;
goto probe_error;
}
dev_info(dev, "cdev:%s lvl:%d registered\n",
cdev_instances[idx].cdev_name,
cdev_instances[idx].max_level);
idx++;
}
of_node_put(np);
return 0;
probe_error:
of_node_put(subsys_np);
of_node_put(np);
inst_cnt = idx;
userspace_cdev_cleanup();
return ret;
}
static int userspace_device_remove(struct platform_device *pdev)
{
userspace_cdev_cleanup();
return 0;
}
static const struct of_device_id userspace_device_match[] = {
{.compatible = "qcom,userspace-cooling-devices"},
{}
};
static struct platform_driver userspace_cdev_driver = {
.probe = userspace_device_probe,
.remove = userspace_device_remove,
.driver = {
.name = USERSPACE_CDEV_DRIVER,
.of_match_table = userspace_device_match,
},
};
static int __init userspace_cdev_init(void)
{
return platform_driver_register(&userspace_cdev_driver);
}
module_init(userspace_cdev_init);
static void __exit userspace_cdev_exit(void)
{
platform_driver_unregister(&userspace_cdev_driver);
}
module_exit(userspace_cdev_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Userspace cooling device driver");