mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 03:27:03 +02:00
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:
parent
83cf3de091
commit
9408ecee82
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
188
drivers/thermal/qcom/qti_userspace_cdev.c
Normal file
188
drivers/thermal/qcom/qti_userspace_cdev.c
Normal 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");
|
||||
Loading…
Reference in New Issue
Block a user