Loading drivers/thermal/qcom/Kconfig +11 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,17 @@ config REGULATOR_COOLING_DEVICE If you want this support, you should say Y here. config QTI_RPM_SMD_COOLING_DEVICE bool "Qualcomm Technologies Inc. RPM SMD cooling device driver" depends on MSM_RPM_SMD && THERMAL_OF help This implements a mitigation device to send temperature band level to RPM hardware via SMD protocol. This mitigation device will be used by temperature reliability rules to restrict a railway at predefined voltage corner using RPM hardware. If you want this support, you should say Y here. config MSM_BCL_PERIPHERAL_CTL bool "BCL driver to control the PMIC BCL peripheral" depends on SPMI && THERMAL_OF Loading drivers/thermal/qcom/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ obj-$(CONFIG_QTI_QMI_COOLING_DEVICE) += thermal_mitigation_device_service_v01.o obj-$(CONFIG_QTI_THERMAL_LIMITS_DCVS) += msm_lmh_dcvs.o lmh_dbg.o obj-$(CONFIG_QTI_AOP_REG_COOLING_DEVICE) += regulator_aop_cdev.o obj-$(CONFIG_REGULATOR_COOLING_DEVICE) += regulator_cdev.o obj-$(CONFIG_QTI_RPM_SMD_COOLING_DEVICE) += rpm_smd_cooling_device.o obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o obj-$(CONFIG_QTI_CPU_ISOLATE_COOLING_DEVICE) += cpu_isolate.o obj-$(CONFIG_QTI_LMH_CPU_VDD_COOLING_DEVICE) += lmh_cpu_vdd_cdev.o Loading drivers/thermal/qcom/rpm_smd_cooling_device.c 0 → 100644 +200 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018, 2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/thermal.h> #include <linux/err.h> #include <soc/qcom/rpm-smd.h> #define RPM_SMD_CDEV_DRIVER "rpm-smd-cooling-device" #define RPM_SMD_RES_TYPE 0x6d726874 #define RPM_SMD_RES_ID 0 #define RPM_SMD_KEY 1 enum rpm_smd_temp_band { RPM_SMD_COLD_CRITICAL = 1, RPM_SMD_COLD, RPM_SMD_COOL, RPM_SMD_NORMAL, RPM_SMD_WARM, RPM_SMD_HOT, RPM_SMD_HOT_CRITICAL, RPM_SMD_TEMP_MAX_NR, }; struct rpm_smd_cdev { struct thermal_cooling_device *cool_dev; char dev_name[THERMAL_NAME_LENGTH]; unsigned int state; struct msm_rpm_request *rpm_handle; }; static int rpm_smd_send_request_to_rpm(struct rpm_smd_cdev *rpm_smd_dev, unsigned int state) { unsigned int band; int msg_id, ret; if (!rpm_smd_dev || !rpm_smd_dev->rpm_handle) { pr_err("Invalid RPM SMD handle\n"); return -EINVAL; } if (rpm_smd_dev->state == state) return 0; /* if state is zero, then send RPM_SMD_NORMAL band */ if (!state) band = RPM_SMD_NORMAL; else band = state; ret = msm_rpm_add_kvp_data(rpm_smd_dev->rpm_handle, RPM_SMD_KEY, (const uint8_t *)&band, (int)sizeof(band)); if (ret) { pr_err("Adding KVP data failed. err:%d\n", ret); return ret; } msg_id = msm_rpm_send_request(rpm_smd_dev->rpm_handle); if (!msg_id) { pr_err("RPM SMD send request failed\n"); return -ENXIO; } ret = msm_rpm_wait_for_ack(msg_id); if (ret) { pr_err("RPM SMD wait for ACK failed. err:%d\n", ret); return ret; } rpm_smd_dev->state = state; pr_debug("Requested RPM SMD band:%d for %s\n", band, rpm_smd_dev->dev_name); return ret; } static int rpm_smd_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { *state = RPM_SMD_TEMP_MAX_NR - 1; return 0; } static int rpm_smd_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { struct rpm_smd_cdev *rpm_smd_dev = cdev->devdata; int ret = 0; if (state > (RPM_SMD_TEMP_MAX_NR - 1)) state = RPM_SMD_TEMP_MAX_NR - 1; ret = rpm_smd_send_request_to_rpm(rpm_smd_dev, (unsigned int)state); if (ret) return ret; return ret; } static int rpm_smd_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct rpm_smd_cdev *rpm_smd_dev = cdev->devdata; *state = rpm_smd_dev->state; return 0; } static struct thermal_cooling_device_ops rpm_smd_device_ops = { .get_max_state = rpm_smd_get_max_state, .get_cur_state = rpm_smd_get_cur_state, .set_cur_state = rpm_smd_set_cur_state, }; static int rpm_smd_cdev_remove(struct platform_device *pdev) { struct rpm_smd_cdev *rpm_smd_dev = (struct rpm_smd_cdev *)dev_get_drvdata(&pdev->dev); if (rpm_smd_dev) { if (rpm_smd_dev->cool_dev) thermal_cooling_device_unregister( rpm_smd_dev->cool_dev); rpm_smd_send_request_to_rpm(rpm_smd_dev, RPM_SMD_NORMAL); msm_rpm_free_request(rpm_smd_dev->rpm_handle); } return 0; } static int rpm_smd_cdev_probe(struct platform_device *pdev) { struct rpm_smd_cdev *rpm_smd_dev; int ret = 0; struct device_node *np; np = dev_of_node(&pdev->dev); if (!np) { dev_err(&pdev->dev, "of node not available for rpm smd cooling device\n"); return -EINVAL; } rpm_smd_dev = devm_kzalloc(&pdev->dev, sizeof(*rpm_smd_dev), GFP_KERNEL); if (!rpm_smd_dev) return -ENOMEM; rpm_smd_dev->rpm_handle = msm_rpm_create_request(MSM_RPM_CTX_ACTIVE_SET, RPM_SMD_RES_TYPE, RPM_SMD_RES_ID, 1); if (!rpm_smd_dev->rpm_handle) { dev_err(&pdev->dev, "Creating RPM SMD request handle failed\n"); return -ENXIO; } strlcpy(rpm_smd_dev->dev_name, np->name, THERMAL_NAME_LENGTH); /* Be pro-active and mitigate till we get first vote from TF */ rpm_smd_send_request_to_rpm(rpm_smd_dev, RPM_SMD_COLD); rpm_smd_dev->cool_dev = thermal_of_cooling_device_register( np, rpm_smd_dev->dev_name, rpm_smd_dev, &rpm_smd_device_ops); if (IS_ERR(rpm_smd_dev->cool_dev)) { ret = PTR_ERR(rpm_smd_dev->cool_dev); dev_err(&pdev->dev, "rpm_smd cdev register err:%d\n", ret); rpm_smd_dev->cool_dev = NULL; return ret; } dev_set_drvdata(&pdev->dev, rpm_smd_dev); return ret; } static const struct of_device_id rpm_smd_cdev_of_match[] = { {.compatible = "qcom,rpm-smd-cooling-device", }, {}, }; static struct platform_driver rpm_smd_cdev_driver = { .driver = { .name = RPM_SMD_CDEV_DRIVER, .of_match_table = rpm_smd_cdev_of_match, }, .probe = rpm_smd_cdev_probe, .remove = rpm_smd_cdev_remove, }; builtin_platform_driver(rpm_smd_cdev_driver); MODULE_LICENSE("GPL v2"); Loading
drivers/thermal/qcom/Kconfig +11 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,17 @@ config REGULATOR_COOLING_DEVICE If you want this support, you should say Y here. config QTI_RPM_SMD_COOLING_DEVICE bool "Qualcomm Technologies Inc. RPM SMD cooling device driver" depends on MSM_RPM_SMD && THERMAL_OF help This implements a mitigation device to send temperature band level to RPM hardware via SMD protocol. This mitigation device will be used by temperature reliability rules to restrict a railway at predefined voltage corner using RPM hardware. If you want this support, you should say Y here. config MSM_BCL_PERIPHERAL_CTL bool "BCL driver to control the PMIC BCL peripheral" depends on SPMI && THERMAL_OF Loading
drivers/thermal/qcom/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ obj-$(CONFIG_QTI_QMI_COOLING_DEVICE) += thermal_mitigation_device_service_v01.o obj-$(CONFIG_QTI_THERMAL_LIMITS_DCVS) += msm_lmh_dcvs.o lmh_dbg.o obj-$(CONFIG_QTI_AOP_REG_COOLING_DEVICE) += regulator_aop_cdev.o obj-$(CONFIG_REGULATOR_COOLING_DEVICE) += regulator_cdev.o obj-$(CONFIG_QTI_RPM_SMD_COOLING_DEVICE) += rpm_smd_cooling_device.o obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o obj-$(CONFIG_QTI_CPU_ISOLATE_COOLING_DEVICE) += cpu_isolate.o obj-$(CONFIG_QTI_LMH_CPU_VDD_COOLING_DEVICE) += lmh_cpu_vdd_cdev.o Loading
drivers/thermal/qcom/rpm_smd_cooling_device.c 0 → 100644 +200 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018, 2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/thermal.h> #include <linux/err.h> #include <soc/qcom/rpm-smd.h> #define RPM_SMD_CDEV_DRIVER "rpm-smd-cooling-device" #define RPM_SMD_RES_TYPE 0x6d726874 #define RPM_SMD_RES_ID 0 #define RPM_SMD_KEY 1 enum rpm_smd_temp_band { RPM_SMD_COLD_CRITICAL = 1, RPM_SMD_COLD, RPM_SMD_COOL, RPM_SMD_NORMAL, RPM_SMD_WARM, RPM_SMD_HOT, RPM_SMD_HOT_CRITICAL, RPM_SMD_TEMP_MAX_NR, }; struct rpm_smd_cdev { struct thermal_cooling_device *cool_dev; char dev_name[THERMAL_NAME_LENGTH]; unsigned int state; struct msm_rpm_request *rpm_handle; }; static int rpm_smd_send_request_to_rpm(struct rpm_smd_cdev *rpm_smd_dev, unsigned int state) { unsigned int band; int msg_id, ret; if (!rpm_smd_dev || !rpm_smd_dev->rpm_handle) { pr_err("Invalid RPM SMD handle\n"); return -EINVAL; } if (rpm_smd_dev->state == state) return 0; /* if state is zero, then send RPM_SMD_NORMAL band */ if (!state) band = RPM_SMD_NORMAL; else band = state; ret = msm_rpm_add_kvp_data(rpm_smd_dev->rpm_handle, RPM_SMD_KEY, (const uint8_t *)&band, (int)sizeof(band)); if (ret) { pr_err("Adding KVP data failed. err:%d\n", ret); return ret; } msg_id = msm_rpm_send_request(rpm_smd_dev->rpm_handle); if (!msg_id) { pr_err("RPM SMD send request failed\n"); return -ENXIO; } ret = msm_rpm_wait_for_ack(msg_id); if (ret) { pr_err("RPM SMD wait for ACK failed. err:%d\n", ret); return ret; } rpm_smd_dev->state = state; pr_debug("Requested RPM SMD band:%d for %s\n", band, rpm_smd_dev->dev_name); return ret; } static int rpm_smd_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { *state = RPM_SMD_TEMP_MAX_NR - 1; return 0; } static int rpm_smd_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { struct rpm_smd_cdev *rpm_smd_dev = cdev->devdata; int ret = 0; if (state > (RPM_SMD_TEMP_MAX_NR - 1)) state = RPM_SMD_TEMP_MAX_NR - 1; ret = rpm_smd_send_request_to_rpm(rpm_smd_dev, (unsigned int)state); if (ret) return ret; return ret; } static int rpm_smd_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct rpm_smd_cdev *rpm_smd_dev = cdev->devdata; *state = rpm_smd_dev->state; return 0; } static struct thermal_cooling_device_ops rpm_smd_device_ops = { .get_max_state = rpm_smd_get_max_state, .get_cur_state = rpm_smd_get_cur_state, .set_cur_state = rpm_smd_set_cur_state, }; static int rpm_smd_cdev_remove(struct platform_device *pdev) { struct rpm_smd_cdev *rpm_smd_dev = (struct rpm_smd_cdev *)dev_get_drvdata(&pdev->dev); if (rpm_smd_dev) { if (rpm_smd_dev->cool_dev) thermal_cooling_device_unregister( rpm_smd_dev->cool_dev); rpm_smd_send_request_to_rpm(rpm_smd_dev, RPM_SMD_NORMAL); msm_rpm_free_request(rpm_smd_dev->rpm_handle); } return 0; } static int rpm_smd_cdev_probe(struct platform_device *pdev) { struct rpm_smd_cdev *rpm_smd_dev; int ret = 0; struct device_node *np; np = dev_of_node(&pdev->dev); if (!np) { dev_err(&pdev->dev, "of node not available for rpm smd cooling device\n"); return -EINVAL; } rpm_smd_dev = devm_kzalloc(&pdev->dev, sizeof(*rpm_smd_dev), GFP_KERNEL); if (!rpm_smd_dev) return -ENOMEM; rpm_smd_dev->rpm_handle = msm_rpm_create_request(MSM_RPM_CTX_ACTIVE_SET, RPM_SMD_RES_TYPE, RPM_SMD_RES_ID, 1); if (!rpm_smd_dev->rpm_handle) { dev_err(&pdev->dev, "Creating RPM SMD request handle failed\n"); return -ENXIO; } strlcpy(rpm_smd_dev->dev_name, np->name, THERMAL_NAME_LENGTH); /* Be pro-active and mitigate till we get first vote from TF */ rpm_smd_send_request_to_rpm(rpm_smd_dev, RPM_SMD_COLD); rpm_smd_dev->cool_dev = thermal_of_cooling_device_register( np, rpm_smd_dev->dev_name, rpm_smd_dev, &rpm_smd_device_ops); if (IS_ERR(rpm_smd_dev->cool_dev)) { ret = PTR_ERR(rpm_smd_dev->cool_dev); dev_err(&pdev->dev, "rpm_smd cdev register err:%d\n", ret); rpm_smd_dev->cool_dev = NULL; return ret; } dev_set_drvdata(&pdev->dev, rpm_smd_dev); return ret; } static const struct of_device_id rpm_smd_cdev_of_match[] = { {.compatible = "qcom,rpm-smd-cooling-device", }, {}, }; static struct platform_driver rpm_smd_cdev_driver = { .driver = { .name = RPM_SMD_CDEV_DRIVER, .of_match_table = rpm_smd_cdev_of_match, }, .probe = rpm_smd_cdev_probe, .remove = rpm_smd_cdev_remove, }; builtin_platform_driver(rpm_smd_cdev_driver); MODULE_LICENSE("GPL v2");