156 lines
4.0 KiB
C
156 lines
4.0 KiB
C
/*
|
|
* Copyright (C) 2012-2013 NVIDIA Corporation. All rights reserved.
|
|
*
|
|
* Aleksandr Frid <afrid@nvidia.com>
|
|
* Paul Walmsley <pwalmsley@nvidia.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* To do:
|
|
* - Does not handle more than one DFLL per system.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/thermal.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/err.h>
|
|
#include <linux/platform_data/tegra_edp.h>
|
|
|
|
static struct thermal_cooling_device *cpu_edp_cdev;
|
|
|
|
static int tegra_edp_get_max_state(struct thermal_cooling_device *cdev,
|
|
unsigned long *max_state)
|
|
{
|
|
struct platform_device *pdev = (struct platform_device *)cdev->devdata;
|
|
*max_state = tegra_cpu_edp_count_therm_floors(pdev);
|
|
return 0;
|
|
}
|
|
|
|
static int tegra_edp_get_cur_state(struct thermal_cooling_device *cdev,
|
|
unsigned long *cur_state)
|
|
{
|
|
struct platform_device *pdev = (struct platform_device *)cdev->devdata;
|
|
*cur_state = tegra_cpu_edp_get_thermal_index(pdev);
|
|
return 0;
|
|
}
|
|
|
|
static int tegra_edp_set_cur_state(struct thermal_cooling_device *cdev,
|
|
unsigned long new_state)
|
|
{
|
|
struct platform_device *pdev = (struct platform_device *)cdev->devdata;
|
|
tegra_cpu_edp_update_thermal_index(pdev, new_state);
|
|
return 0;
|
|
}
|
|
|
|
static struct thermal_cooling_device_ops tegra_edp_cooling_ops = {
|
|
.get_max_state = tegra_edp_get_max_state,
|
|
.get_cur_state = tegra_edp_get_cur_state,
|
|
.set_cur_state = tegra_edp_set_cur_state,
|
|
};
|
|
|
|
static int tegra_cpu_edp_cdev_probe(struct platform_device *pdev)
|
|
{
|
|
struct thermal_cooling_device *tcd;
|
|
struct device_node *dn;
|
|
const __be32 *prop;
|
|
struct platform_device *cpu_edp_pdev;
|
|
struct device *dev = &pdev->dev;
|
|
const char *cdev_type;
|
|
int ret = 0;
|
|
|
|
prop = of_get_property(dev->of_node, "act-dev", NULL);
|
|
if (!prop) {
|
|
dev_err(dev,
|
|
"Missing cpu-edp node\n");
|
|
return -ENOENT;
|
|
}
|
|
dn = of_find_node_by_phandle(be32_to_cpup(prop));
|
|
if (!dn) {
|
|
dev_err(dev,
|
|
"Missing cpu-edp node\n");
|
|
return -ENOENT;
|
|
}
|
|
|
|
cpu_edp_pdev = of_find_device_by_node(dn);
|
|
if (!cpu_edp_pdev) {
|
|
dev_err(dev,
|
|
"Missing cpu-edp pdev\n");
|
|
ret = -ENOENT;
|
|
goto error;
|
|
}
|
|
|
|
cdev_type = of_get_property(dev->of_node, "cdev-cap-type", NULL);
|
|
if (IS_ERR_OR_NULL(cdev_type)) {
|
|
dev_err(dev,
|
|
"Missing cpu-edp cap cdev type\n");
|
|
ret = -EINVAL;
|
|
goto error;
|
|
}
|
|
|
|
|
|
if (!tegra_cpu_edp_ready()) {
|
|
ret = -EPROBE_DEFER;
|
|
goto error;
|
|
}
|
|
|
|
|
|
tcd = thermal_cooling_device_register((char *)cdev_type,
|
|
(void *)cpu_edp_pdev,
|
|
&tegra_edp_cooling_ops);
|
|
if (IS_ERR_OR_NULL(tcd)) {
|
|
dev_err(dev,
|
|
"Tegra CPU EDP thermal reaction driver failed to register\n");
|
|
ret = PTR_ERR(tcd);
|
|
goto error;
|
|
}
|
|
|
|
cpu_edp_cdev = tcd;
|
|
|
|
dev_info(dev, "Tegra CPU EDP cooling device registered\n");
|
|
|
|
error:
|
|
of_node_put(dn);
|
|
return ret;
|
|
}
|
|
|
|
static int tegra_cpu_edp_cdev_remove(struct platform_device *pdev)
|
|
{
|
|
thermal_cooling_device_unregister(cpu_edp_cdev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id tegra_cpu_edp_cdev_match[] = {
|
|
{ .compatible = "nvidia,tegra124-cpu-edp-cdev-action", },
|
|
{},
|
|
};
|
|
|
|
static struct platform_driver tegra_cpu_edp_cdev_driver = {
|
|
.driver = {
|
|
.name = "tegra_cpu_edp_action",
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = tegra_cpu_edp_cdev_match,
|
|
},
|
|
.probe = tegra_cpu_edp_cdev_probe,
|
|
.remove = tegra_cpu_edp_cdev_remove,
|
|
};
|
|
|
|
module_platform_driver(tegra_cpu_edp_cdev_driver);
|
|
|
|
MODULE_DESCRIPTION("Tegra CPU EDP thermal reaction driver");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Wei Ni <wni@nvidia.com>");
|