From 9408ecee8255e7335b215ee384eed6649813ea54 Mon Sep 17 00:00:00 2001 From: Rashid Zafar Date: Fri, 4 Nov 2022 15:43:52 -0700 Subject: [PATCH] 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 Signed-off-by: Rashid Zafar --- drivers/thermal/qcom/Kconfig | 9 ++ drivers/thermal/qcom/Makefile | 1 + drivers/thermal/qcom/qti_userspace_cdev.c | 188 ++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 drivers/thermal/qcom/qti_userspace_cdev.c diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig index a4118ffe4d96..ea9fbf657ff7 100644 --- a/drivers/thermal/qcom/Kconfig +++ b/drivers/thermal/qcom/Kconfig @@ -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. + diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile index 12772bcadbbf..51714d52a030 100644 --- a/drivers/thermal/qcom/Makefile +++ b/drivers/thermal/qcom/Makefile @@ -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 diff --git a/drivers/thermal/qcom/qti_userspace_cdev.c b/drivers/thermal/qcom/qti_userspace_cdev.c new file mode 100644 index 000000000000..e1b583155ad6 --- /dev/null +++ b/drivers/thermal/qcom/qti_userspace_cdev.c @@ -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 +#include +#include +#include +#include +#include + +#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");