mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-14 16:46:15 -04:00
drivers: thermal: Snapshot of lmh cpu VDD driver from msm-4.19
Add a snapshot of limits cpu voltage cooling device driver changes
from msm-4.19. This is snapshot as of 'commit <603750db5e89>
("drivers: thermal: validate cdev sysfs cur_state request before
using it")'.
Change-Id: I3e8763df4e0a715407b955939f3d91b6c10f976a
Signed-off-by: Manaf Meethalavalappu Pallikunhi <manafm@codeaurora.org>
This commit is contained in:
parent
03d2764796
commit
8e2eb22c5d
3 changed files with 190 additions and 0 deletions
|
|
@ -172,3 +172,12 @@ config MAX31760_FAN_CONTROLLER
|
|||
This driver uses i2c bus to control registers for setting
|
||||
different fan speed. Also, this driver initializes the power for
|
||||
the fan controller.
|
||||
|
||||
config QTI_LMH_CPU_VDD_COOLING_DEVICE
|
||||
tristate "QTI CPU LMH VDD Voltage cooling devices"
|
||||
depends on THERMAL_OF && QTI_THERMAL
|
||||
help
|
||||
This enables the QTI limits hardware CPU VDD cooling devices.
|
||||
These cooling devices will be used by QTI chipset to place a
|
||||
request to limits hardware for a minimum CPU railway voltage
|
||||
corner at cold temperature condition.
|
||||
|
|
|
|||
|
|
@ -25,3 +25,4 @@ obj-$(CONFIG_QTI_RPM_SMD_COOLING_DEVICE) += rpm_smd_cooling_device.o
|
|||
obj-$(CONFIG_QTI_LIMITS_ISENSE_CDSP) += msm_isense_cdsp.o
|
||||
obj-$(CONFIG_QTI_DDR_COOLING_DEVICE) += ddr_cdev.o
|
||||
obj-$(CONFIG_MAX31760_FAN_CONTROLLER) += max31760_fan.o
|
||||
obj-$(CONFIG_QTI_LMH_CPU_VDD_COOLING_DEVICE) += lmh_cpu_vdd_cdev.o
|
||||
|
|
|
|||
180
drivers/thermal/qcom/lmh_cpu_vdd_cdev.c
Normal file
180
drivers/thermal/qcom/lmh_cpu_vdd_cdev.c
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/cpu_cooling.h>
|
||||
#include <linux/idr.h>
|
||||
|
||||
#define LMH_CPU_VDD_MAX_LVL 1
|
||||
#define LIMITS_CLUSTER_MIN_FREQ_OFFSET 0x3C0
|
||||
|
||||
struct lmh_cpu_vdd_cdev {
|
||||
struct list_head node;
|
||||
int id;
|
||||
bool cpu_vdd_state;
|
||||
void *min_freq_reg;
|
||||
struct thermal_cooling_device *cdev;
|
||||
};
|
||||
|
||||
static DEFINE_IDA(lmh_cpu_vdd_ida);
|
||||
static DEFINE_MUTEX(lmh_cpu_vdd_lock);
|
||||
static LIST_HEAD(lmh_cpu_vdd_list);
|
||||
|
||||
static int lmh_cpu_vdd_set_cur_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long state)
|
||||
{
|
||||
struct lmh_cpu_vdd_cdev *vdd_cdev = cdev->devdata;
|
||||
|
||||
if (state > LMH_CPU_VDD_MAX_LVL)
|
||||
return -EINVAL;
|
||||
|
||||
state = !!state;
|
||||
/* Check if the old cooling action is same as new cooling action */
|
||||
if (vdd_cdev->cpu_vdd_state == state)
|
||||
return 0;
|
||||
|
||||
writel_relaxed(state, vdd_cdev->min_freq_reg);
|
||||
vdd_cdev->cpu_vdd_state = state;
|
||||
|
||||
pr_debug("%s limits CPU VDD restriction for %s\n",
|
||||
state ? "Triggered" : "Cleared", vdd_cdev->cdev->type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lmh_cpu_vdd_get_cur_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct lmh_cpu_vdd_cdev *lmh_cpu_vdd_cdev = cdev->devdata;
|
||||
|
||||
*state = (lmh_cpu_vdd_cdev->cpu_vdd_state) ?
|
||||
LMH_CPU_VDD_MAX_LVL : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lmh_cpu_vdd_get_max_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
*state = LMH_CPU_VDD_MAX_LVL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_cooling_device_ops lmh_cpu_vdd_cooling_ops = {
|
||||
.get_max_state = lmh_cpu_vdd_get_max_state,
|
||||
.get_cur_state = lmh_cpu_vdd_get_cur_state,
|
||||
.set_cur_state = lmh_cpu_vdd_set_cur_state,
|
||||
};
|
||||
|
||||
|
||||
static int lmh_cpu_vdd_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = -1;
|
||||
struct lmh_cpu_vdd_cdev *lmh_cpu_vdd_cdev;
|
||||
struct device_node *dn = pdev->dev.of_node;
|
||||
uint32_t min_reg;
|
||||
char cdev_name[THERMAL_NAME_LENGTH] = "";
|
||||
const __be32 *addr;
|
||||
|
||||
lmh_cpu_vdd_cdev = devm_kzalloc(&pdev->dev, sizeof(*lmh_cpu_vdd_cdev),
|
||||
GFP_KERNEL);
|
||||
if (!lmh_cpu_vdd_cdev)
|
||||
return -ENOMEM;
|
||||
|
||||
addr = of_get_address(dn, 0, NULL, NULL);
|
||||
if (!addr) {
|
||||
dev_err(&pdev->dev, "Property llm-base-addr not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
min_reg = be32_to_cpu(addr[0]) + LIMITS_CLUSTER_MIN_FREQ_OFFSET;
|
||||
lmh_cpu_vdd_cdev->min_freq_reg = devm_ioremap(&pdev->dev, min_reg, 0x4);
|
||||
if (!lmh_cpu_vdd_cdev->min_freq_reg) {
|
||||
dev_err(&pdev->dev, "lmh cpu vdd register remap failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_lock(&lmh_cpu_vdd_lock);
|
||||
ret = ida_simple_get(&lmh_cpu_vdd_ida, 0, 0, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to create ida\n");
|
||||
goto unlock_exit;
|
||||
}
|
||||
lmh_cpu_vdd_cdev->id = ret;
|
||||
ret = 0;
|
||||
|
||||
snprintf(cdev_name, THERMAL_NAME_LENGTH, "lmh-cpu-vdd%d",
|
||||
lmh_cpu_vdd_cdev->id);
|
||||
|
||||
lmh_cpu_vdd_cdev->cdev = thermal_of_cooling_device_register(
|
||||
dn,
|
||||
cdev_name,
|
||||
lmh_cpu_vdd_cdev,
|
||||
&lmh_cpu_vdd_cooling_ops);
|
||||
if (IS_ERR(lmh_cpu_vdd_cdev->cdev)) {
|
||||
ret = PTR_ERR(lmh_cpu_vdd_cdev->cdev);
|
||||
dev_err(&pdev->dev, "Cooling register failed for %s, ret:%d\n",
|
||||
cdev_name, ret);
|
||||
lmh_cpu_vdd_cdev->cdev = NULL;
|
||||
goto remove_ida;
|
||||
}
|
||||
list_add(&lmh_cpu_vdd_cdev->node, &lmh_cpu_vdd_list);
|
||||
mutex_unlock(&lmh_cpu_vdd_lock);
|
||||
|
||||
pr_debug("Cooling device [%s] registered.\n", cdev_name);
|
||||
|
||||
return ret;
|
||||
|
||||
remove_ida:
|
||||
ida_simple_remove(&lmh_cpu_vdd_ida, lmh_cpu_vdd_cdev->id);
|
||||
|
||||
unlock_exit:
|
||||
mutex_unlock(&lmh_cpu_vdd_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lmh_cpu_vdd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lmh_cpu_vdd_cdev *lmh_cpu_vdd, *c_next;
|
||||
|
||||
mutex_lock(&lmh_cpu_vdd_lock);
|
||||
list_for_each_entry_safe(lmh_cpu_vdd, c_next,
|
||||
&lmh_cpu_vdd_list, node) {
|
||||
if (lmh_cpu_vdd->cdev) {
|
||||
thermal_cooling_device_unregister(
|
||||
lmh_cpu_vdd->cdev);
|
||||
lmh_cpu_vdd->cdev = NULL;
|
||||
}
|
||||
ida_simple_remove(&lmh_cpu_vdd_ida, lmh_cpu_vdd->id);
|
||||
list_del(&lmh_cpu_vdd->node);
|
||||
}
|
||||
mutex_unlock(&lmh_cpu_vdd_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const struct of_device_id lmh_cpu_vdd_match[] = {
|
||||
{ .compatible = "qcom,lmh-cpu-vdd", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver lmh_cpu_vdd_driver = {
|
||||
.probe = lmh_cpu_vdd_probe,
|
||||
.remove = lmh_cpu_vdd_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = lmh_cpu_vdd_match,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(lmh_cpu_vdd_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
Loading…
Reference in a new issue